The things that are automatically treated as rvalues are things without names, and things that (very shortly) will not have a name (in the return value case).
T&& t
has a name, it is t
.
The reason why rvalues are those things is that referring to them after that point of use is next to impossible.
T&&
is the type rvalue reference. An rvalue reference can only bind to an rvalue (without a static_cast
being involved), but it is otherwise an lvalue of type rvalue reference.
The fact it is of type rvalue reference only matters during its construction, and if you do decltype(variable_name)
. It is otherwise just another lvalue of reference type.
std::move(t)
does a return static_cast<T&&>(t);
and returns an rvalue reference.
The rules that govern this are written in standardese in the C++ standard. A copy/paste of them won't be all that useful, because they are not that easy to understand.
The first general rule is, you get an implicit move (aka, parameter that binds to an rvalue reference argument) when you return a named value from a function, or when a value has no name, or when a function explicitly returns an rvalue reference.
Second, that only rvalue references and const&
can bind to rvalues.
Third, reference lifetime extension on temporary values occurs when directly bound to a reference outside of a constructor. (as only rvalue references and const&
can directly bind to a temporary, this only applies to them)
Forth, T&&
isn't always an rvalue reference. If T
is of type X&
or X const&
, then reference collapsing turns T&&
into X&
or X const&
.
Finally, T&&
in a type deduction context will deduce T
as X
, X&
, X const&
or X const&&
depending on the type of the argument, and hence can act as a "forwarding reference".