The following C++11 code does not compile:
struct T {};
void f(T&&) { }
void g(T&& t) { f(t); }
int main()
{
g(T());
}
The correct way to do this is:
void g(T&& t) { f(move(t)); }
This is very difficult to explain in the correct natural language terminology. The parameter t seems to lose its “&&” status which it needs to have reinstated with the std::move.
What do you call the T() in g(T()) ?
What do you call the T&& in g(T&& t) ?
What do you call the t in g(T&& t) ?
What do you call the t in f(t) and f(move(t)) ?
What do you call the return value of move(t)?
What do you call the overall effect?
Which section(s) of the standard deal with this issue?
The key point is that a parameter
T&& bcan only bind to an rvalue, but when referred to later the expressionbis an lvalue.So the argument to the function must be an rvalue, but inside the function body the parameter is an lvalue because by then you’ve bound a reference to it and given it a name and it’s no longer an unnamed temporary.
An expression has a type (e.g.
int,stringetc.) and it has a value category (e.g. lvalue or rvalue) and these two things are distinct.A named variable which is declared as
T&& bhas type “rvalue reference toT” and can only be bound to an rvalue, but when you later use that reference the expressionbhas value category “lvalue”, because it has a name and refers to some object (whatever the reference is bound to, even though that was an rvalue.) This means to passbto another function which takes an rvalue you can’t just sayf(b)becausebis an lvalue, so you must convert it (back) to an rvalue, viastd::move(b).