This is a question of terminology. If I have this:
#include <vector>
void g(std::vector<int>&& arg);
void f0(std::vector<int>&& v) {
static_assert(std::is_same<decltype(v), std::vector<int>&&>::value); // Looks like v is an rvalue reference.
static_assert(std::is_same<decltype((v)), std::vector<int>&>::value);
static_assert(std::is_same<std::decay<decltype(v)>::type, std::vector<int>>::value);
return g(std::move(v)); // Fine.
}
then what type is v
? If you are talking about calling f0
, you'd say "f0
takes an rvalue reference" (right?) but within f0
, v
isn't an rvalue reference, or else the std::move
wouldn't be required? Right? But the static_assert
showed that it is an rvalue, right?
Similarly:
void f1(std::vector<int>&& v) {
static_assert(std::is_same<decltype(v), std::vector<int>&&>::value);
static_assert(std::is_same<decltype((v)), std::vector<int>&>::value);
static_assert(std::is_same<std::decay<decltype(v)>::type, std::vector<int>>::value);
return g(v); // Error: cannot bind rvalue reference of type 'std::vector<int>&&' to lvalue of type 'std::vector<int>'.
// So is v just a std::vector<int>?
}
Local rvalue references act the same way:
void f2(std::vector<int>&& v) {
std::vector<int>&& vv = std::move(v);
static_assert(std::is_same<decltype(vv), decltype(v)>::value, "They are the same decltype. So being an argument isn't magic.");
static_assert(std::is_same<decltype(vv), std::vector<int>&&>::value);
static_assert(std::is_same<decltype((vv)), std::vector<int>&>::value);
static_assert(std::is_same<std::decay<decltype(vv)>::type, std::vector<int>>::value);
return g(vv); // Error: cannot bind rvalue reference of type 'std::vector<int>&&' to lvalue of type 'std::vector<int>'
}
What is the correct terminology to describe the type of v
? Is it correct to say f0
takes an rvalue reference? If v
is an rvalue reference, what's the terminology to say that an rvalue reference can't be used to call a function taking an rvalue reference?
The declared type of the variable named v
is std::vector<int>&&
. This type is read "rvalue reference to std::vector
".
The name v
can appears in an expression. Expressions never have reference type [expr.type]/1. But expressions have a value category. When the name v
appears in an expression as in v[0]
, the subexpression v
has type std::vector<int>
and its value category is lvalue. This is the case of almost all id-expression (expressions that are just a name).
decltype(v)
gives the declared type of the variable v
.
decltype(expression)
gives :
expression
if expression
is a lvalue, expression
if expression
is a xvalue, expression
if expression
is a prvalue.More details are given in [dcl.dcl]/1.