当函数采用右值引用时,函数中该变量的类型是什么?
When a function takes an rvalue reference, what is the type of that variable within the function?
这是一个术语问题。如果我有这个:
#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
是右值引用,那么右值引用不能用于调用采用右值引用的函数的术语是什么?
您将类型与值类别混淆了,在您看来,这非常容易做到。
是的,该函数采用 "rvalue reference to std::vector<int>
" 类型的参数。该引用可以在调用点从 std::vector<int>
类型的右值表达式初始化。
函数内部表达式v
的类型,当你开始尝试使用它时,不是std::vector<int>&&
; "decays" 的参考排序。这只是引用工作机制的一部分。 (decltype
在这方面有点奇怪。)出于所有意图和目的,您最终得到类型为 std::vector<int>
的 lvalue 表达式。无论如何,在这一点上类型是无关紧要的;关键是名称 v
是一个左值,要再次将其变成右值,您需要 std::move
.
But the static_assert showed that it is an rvalue, right?
没有。 "rvalue reference" 描述了各种类型。 "rvalue" 是一个值类别。您可能想知道他们为什么选择这样令人困惑的术语。我也是。
名为 v
的变量的 声明类型 是 std::vector<int>&&
。这种类型被读作“rvalue reference to std::vector
”。
名称 v
可以出现在 表达式 中。表达式从来没有引用类型 [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(表达式只是一个名称)。
decltype(v)
给出变量的声明类型v
.
decltype(expression)
给出:
- a lvalue-reference 到
expression
的类型,如果 expression
是左值,
- a rvalue-reference 到
expression
的类型,如果 expression
是一个 xvalue,
- 如果
expression
是纯右值,expression
的类型。
[dcl.dcl]/1 中提供了更多详细信息。
这是一个术语问题。如果我有这个:
#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
是右值引用,那么右值引用不能用于调用采用右值引用的函数的术语是什么?
您将类型与值类别混淆了,在您看来,这非常容易做到。
是的,该函数采用 "rvalue reference to std::vector<int>
" 类型的参数。该引用可以在调用点从 std::vector<int>
类型的右值表达式初始化。
函数内部表达式v
的类型,当你开始尝试使用它时,不是std::vector<int>&&
; "decays" 的参考排序。这只是引用工作机制的一部分。 (decltype
在这方面有点奇怪。)出于所有意图和目的,您最终得到类型为 std::vector<int>
的 lvalue 表达式。无论如何,在这一点上类型是无关紧要的;关键是名称 v
是一个左值,要再次将其变成右值,您需要 std::move
.
But the static_assert showed that it is an rvalue, right?
没有。 "rvalue reference" 描述了各种类型。 "rvalue" 是一个值类别。您可能想知道他们为什么选择这样令人困惑的术语。我也是。
名为 v
的变量的 声明类型 是 std::vector<int>&&
。这种类型被读作“rvalue reference to std::vector
”。
名称 v
可以出现在 表达式 中。表达式从来没有引用类型 [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(表达式只是一个名称)。
decltype(v)
给出变量的声明类型v
.
decltype(expression)
给出:
- a lvalue-reference 到
expression
的类型,如果expression
是左值, - a rvalue-reference 到
expression
的类型,如果expression
是一个 xvalue, - 如果
expression
是纯右值,expression
的类型。
[dcl.dcl]/1 中提供了更多详细信息。