Type and value category are independent. Your function parameter (when passed an rvalue, maybe cv-qualified) has the type "rvalue reference to cv T",
but it is an lvalue.)
The compiler only automatically moves from
rvalues.
This is a pretty common pitfall. See this post:
http://www.cplusplus.com/forum/general/219122/
The rule of thumb is this:
If the object has a name, its value category is lvalue.
If a function accepts a rvalue reference, then it should almost always call move() on that reference.
If a function accepts a forwarding reference, then it should almost always call forward() on that reference.
The latter guideline (use
forward()) applies here, because of a special rule about the type
T&& for deduced
T.
This is where ref-collapsing applies: if you pass
doCopy() an lvalue (ignoring cv-qualifiers), the deduced type is
T&& & --> T&; which can't be moved from safely. You can safely move if and only if the argument is actually an rvalue, in which case you get the
T&& && --> T&& like you mentioned.
Go read Thomas Becker's famous article, here:
http://thbecker.net/articles/rvalue_references/section_01.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
// only binds rvalues
void move_me(A&& arg)
{
// arg's value category is lvalue; arg has type rvalue reference to A
// We know that the argument can be moved from, because the parameter is bound to an rvalue
// To actually move from it,
use_me(std::move(arg));
}
// binds every value category; the type of arg is not necessarily "rvalue-reference to T".
template <typename T>
void forward_me(T&& arg)
{
// the value category of arg is lvalue; the type of arg is deduced
// we wish to move arg if and only if arg is bound to an rvalue, otherwise copy
foo(std::forward<T>(arg));
}
| |