这是术语问题。如果我有这个:
#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.
}
那么v
是什么类型?如果您在谈论调用f0
,您会说“ f0
具有右值引用”(对吗?),但是在f0
中,v
不是右值引用,还是不需要std::move
?对?但是static_assert
表明它是右值,对吧?
类似地:
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>?
}
本地右值引用的行为相同:
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>'
}
描述v
类型的正确术语是什么?说f0
是否使用右值引用是否正确?如果v
是右值引用,那么用什么术语说不能使用右值引用来调用带有右值引用的函数?
答案 0 :(得分:3)
名为v
的变量的声明类型为std::vector<int>&&
。将该类型读取为“ 对 std::vector
的右值引用”。
名称v
可以出现在表达式中。表达式永远不会具有引用类型[expr.type]/1。但是表达式有一个value category。当名称v
出现在v[0]
中的表达式中时,子表达式v
的类型为std::vector<int>
,其值类别为 lvalue 。几乎所有id-expression(表达式只是名称)都是这种情况。
decltype(v)
给出变量v
的声明类型。
decltype(expression)
给出:
expression
是左值,则对expression
类型的左值引用expression
是xvalue,则对expression
类型的右值引用expression
是prvalue,则expression
的类型。[dcl.dcl]/1中提供了更多详细信息。
答案 1 :(得分:2)
您正在将类型与值类别混淆,这在您的辩护中非常容易做到。
是的,该函数接受类型为“ std::vector<int>
的右值引用”的参数。可以从呼叫现场的std::vector<int>
类型的右值表达式初始化此引用。
开始尝试使用函数内部的表达式v
的类型不是std::vector<int>&&
;参考类型的“衰减”。这只是引用工作原理的一部分。 (decltype
在这方面有些奇怪。)出于所有意图和目的,您最终得到类型为std::vector<int>
的 lvalue 表达式。无论如何,在这一点上类型是无关紧要的。关键是名称v
是一个左值,而再次使其变为右值,则需要std::move
。
但是static_assert显示它是一个右值,对吧?
不。 “右值参考”描述了各种类型。 “ rvalue”是值类别。您可能想知道为什么他们选择了这种令人困惑的术语。我也是。