C++ 右值引用请求
C++ rvalue reference requestion
我对右值引用感到困惑,
is_rvalue_reference<decltype(a)>::value
表示a
变量是右值引用,
但不能将其传递给 hello(int &&)
函数。
#include <iostream>
#include <string>
#include <array>
using std::cout;
using std::endl;
using std::boolalpha;
using std::string;
using std::is_rvalue_reference;
using std::move;
void hello(int && z) {};
int main(void) {
int && a = 20;
// a is_xvalue: true
cout << "a is_xvalue: " << boolalpha << is_rvalue_reference<decltype(a)>::value << endl;
// error C2664:
// 'void hello(int &&)': cannot convert argument 1 from 'int' to 'int &&'
hello(a);
// compile ok.
hello(move(a));
return 0;
}
Types and value categories是两个独立的东西。
Each C++ expression (an operator with its operands, a literal, a variable name, etc.) is characterized by two independent properties: a type and a value category.
a
的类型是int&&
,即右值引用。但是作为命名变量,a
是一个左值,不能绑定到右值引用。这似乎令人困惑,但请尝试分别考虑它们。
(强调我的)
The following expressions are lvalue expressions:
- the name of a variable, a function, a template parameter object (since C++20), or a data member, regardless of type, such as std::cin
or std::endl. Even if the variable's type is rvalue reference, the
expression consisting of its name is an lvalue expression;
虽然 a
看起来像是 r 值,但实际上不是。
a
本身是一个包含右值引用的左值。
可以取a
的地址,但不能取move(a)
的地址。
请查看此 article 以真正了解专门针对您的问题的价值类别。
a
可以是标识符,也可以是表达式。标识符和表达式是不同的东西。表达式有types and value categories,标识符只有类型
在行
int&& a = 20;
a
是标识符(id-expression),不是表达式。它有类型 int&&
并且没有值类别。 decltype(a)
将 return 类型 int&&
:
If the argument is an unparenthesized id-expression ..., then decltype
yields the type of the entity named by this expression.
行中
hello(a);
a
是一个表达式,不是标识符。现在它有一个值类别,它是 lvalue,因为 a
是一个变量的名称(类型无关紧要):
The following expressions are lvalue expressions:
- the name of a variable, ... Even if the variable's type is rvalue reference, the expression consisting of its name is an lvalue expression; ...
它还有一个类型,就是int
,因为标准的reads:
If an expression initially has the type “reference to T
”, the type is adjusted to T
prior to any further analysis.
要将 a
视为 decltype
中的表达式,请将其括起来:decltype((a))
将 return int&
,因为对于 T
类型的左值 表达式 it returns T&
:
If the argument is any other expression of type T
, and
- if the value category of expression is xvalue, then
decltype
yields T&&
;
- if the value category of expression is lvalue, then
decltype
yields T&
;
int&&
in hello(int&&)
无法绑定到具有 lvalue 值类别的表达式,编译失败。
在行
hello(std::move(a));
std::move(a)
是一个表达式。它的值类别是xvalue:
The following expressions are xvalue expressions:
- a function call or an overloaded operator expression, whose return type is rvalue reference to object, such as
std::move(x)
; ...
它的类型也是int
。 decltype(std::move(a))
将 return int&&
,因为对于 xvalue 类型的表达式 T
it returns T&&
. hello(int&&)
中的int&&
可以绑定到int
类型的xvalues,编译成功。
我对右值引用感到困惑,
is_rvalue_reference<decltype(a)>::value
表示a
变量是右值引用,
但不能将其传递给 hello(int &&)
函数。
#include <iostream>
#include <string>
#include <array>
using std::cout;
using std::endl;
using std::boolalpha;
using std::string;
using std::is_rvalue_reference;
using std::move;
void hello(int && z) {};
int main(void) {
int && a = 20;
// a is_xvalue: true
cout << "a is_xvalue: " << boolalpha << is_rvalue_reference<decltype(a)>::value << endl;
// error C2664:
// 'void hello(int &&)': cannot convert argument 1 from 'int' to 'int &&'
hello(a);
// compile ok.
hello(move(a));
return 0;
}
Types and value categories是两个独立的东西。
Each C++ expression (an operator with its operands, a literal, a variable name, etc.) is characterized by two independent properties: a type and a value category.
a
的类型是int&&
,即右值引用。但是作为命名变量,a
是一个左值,不能绑定到右值引用。这似乎令人困惑,但请尝试分别考虑它们。
(强调我的)
The following expressions are lvalue expressions:
- the name of a variable, a function, a template parameter object (since C++20), or a data member, regardless of type, such as std::cin or std::endl. Even if the variable's type is rvalue reference, the expression consisting of its name is an lvalue expression;
虽然 a
看起来像是 r 值,但实际上不是。
a
本身是一个包含右值引用的左值。
可以取a
的地址,但不能取move(a)
的地址。
请查看此 article 以真正了解专门针对您的问题的价值类别。
a
可以是标识符,也可以是表达式。标识符和表达式是不同的东西。表达式有types and value categories,标识符只有类型
在行
int&& a = 20;
a
是标识符(id-expression),不是表达式。它有类型int&&
并且没有值类别。decltype(a)
将 return 类型int&&
:If the argument is an unparenthesized id-expression ..., then
decltype
yields the type of the entity named by this expression.行中
hello(a);
a
是一个表达式,不是标识符。现在它有一个值类别,它是 lvalue,因为a
是一个变量的名称(类型无关紧要):The following expressions are lvalue expressions:
- the name of a variable, ... Even if the variable's type is rvalue reference, the expression consisting of its name is an lvalue expression; ...
它还有一个类型,就是
int
,因为标准的reads:If an expression initially has the type “reference to
T
”, the type is adjusted toT
prior to any further analysis.要将
a
视为decltype
中的表达式,请将其括起来:decltype((a))
将 returnint&
,因为对于T
类型的左值 表达式 it returnsT&
:If the argument is any other expression of type
T
, and- if the value category of expression is xvalue, then
decltype
yieldsT&&
; - if the value category of expression is lvalue, then
decltype
yieldsT&
;
int&&
inhello(int&&)
无法绑定到具有 lvalue 值类别的表达式,编译失败。在行
hello(std::move(a));
std::move(a)
是一个表达式。它的值类别是xvalue:The following expressions are xvalue expressions:
- a function call or an overloaded operator expression, whose return type is rvalue reference to object, such as
std::move(x)
; ...
它的类型也是
int
。decltype(std::move(a))
将 returnint&&
,因为对于 xvalue 类型的表达式T
it returnsT&&
.hello(int&&)
中的int&&
可以绑定到int
类型的xvalues,编译成功。- a function call or an overloaded operator expression, whose return type is rvalue reference to object, such as