std::move(a).m 是一个 xvalue 还是一个 prvalue?
Is std::move(a).m an xvalue or a prvalue?
假设 m
是非引用类型的非静态数据成员 (T
)。根据 cppreference,std::move(a).m
是 c++11 之前的纯右值。我猜它应该是 c++11 之后的一个 xvalue。如果我错了,请纠正我。
但是在 c++14 (visual studio, clang, gcc) 中 decltype(std::move(a).m)
仍然是 T
(不是 T&&
),这表明 std::move(a).m
仍然是纯右值。那么 std::move(a).m
是一个 xvalue 还是一个 prvalue?
std::move(a).m
是一个 xvalue。
[basic.lval]:
中的新措辞使这一点更加清晰
- A prvalue is an expression whose evaluation initializes an object or a bit-field, or computes the value of the operand of an operator, as specified by the context in which it appears.
- An xvalue is a glvalue that denotes an object or bit-field whose resources can be reused (usually because it is near the end of its lifetime).
根据这些定义,std::move(a).m
是一个 xvalue 而不是 prvalue,因为它表示一个对象。
我认为最好的思考方式是左值具有身份并且右值可以安全地移动 - 左值具有身份并且不能安全地离开,xvalues 具有身份并且可以安全地离开,并且prvalues 没有身份并且可以安全地移动。这种分类法使这类问题更容易推理。
另外[expr]里有个注释,比较具体:
[ Note: An expression is an xvalue if it is: [...]
— a cast to an rvalue reference to object type,
— a class member access expression designating a non-static data member of non-reference type in which the object expression is an xvalue, or [...]
—end note ]
std::move(a)
是对右值引用的强制转换,xvalue 也是如此。 std::move(a).m
是 xvalue 的 class 成员访问,xvalue 也是。
至于decltype(std::move(a).m)
。请注意,该词本身来自 declared type。 decltype(e)
含义的规则很复杂,来自 [dcl.type.simple]:
For an expression e
, the type denoted by decltype(e)
is defined as follows:
— if e
is an unparenthesized id-expression naming an lvalue or reference introduced from the identifier-list of a decomposition declaration, decltype(e)
is the referenced type as given in the specification of the
decomposition declaration (8.5);
— otherwise, if e
is an unparenthesized id-expression or an unparenthesized class member access (5.2.5),
decltype(e)
is the type of the entity named by e
. If there is no such entity, or if e
names a set of overloaded functions, the program is ill-formed;
— otherwise, if e
is an xvalue, decltype(e)
is T&&
, where T
is the type of e
;
— otherwise, if e
is an lvalue, decltype(e)
is T&
, where T
is the type of e
;
— otherwise, decltype(e)
is the type of e
.
在这种情况下,我们有一个 class 成员访问权限,因此您只获得 m
的类型 - 即 M
而不是 M&&
。在某种程度上这是有道理的,您要求 m
的声明类型并且您得到了 m
的声明类型。
如果您想对其进行正确分类,可以使用一组额外的括号强制忽略该项目符号(显然):decltype((std::move(a).m))
会给您 M&&
.
假设 m
是非引用类型的非静态数据成员 (T
)。根据 cppreference,std::move(a).m
是 c++11 之前的纯右值。我猜它应该是 c++11 之后的一个 xvalue。如果我错了,请纠正我。
但是在 c++14 (visual studio, clang, gcc) 中 decltype(std::move(a).m)
仍然是 T
(不是 T&&
),这表明 std::move(a).m
仍然是纯右值。那么 std::move(a).m
是一个 xvalue 还是一个 prvalue?
std::move(a).m
是一个 xvalue。
[basic.lval]:
中的新措辞使这一点更加清晰
- A prvalue is an expression whose evaluation initializes an object or a bit-field, or computes the value of the operand of an operator, as specified by the context in which it appears.
- An xvalue is a glvalue that denotes an object or bit-field whose resources can be reused (usually because it is near the end of its lifetime).
根据这些定义,std::move(a).m
是一个 xvalue 而不是 prvalue,因为它表示一个对象。
我认为最好的思考方式是左值具有身份并且右值可以安全地移动 - 左值具有身份并且不能安全地离开,xvalues 具有身份并且可以安全地离开,并且prvalues 没有身份并且可以安全地移动。这种分类法使这类问题更容易推理。
另外[expr]里有个注释,比较具体:
[ Note: An expression is an xvalue if it is: [...]
— a cast to an rvalue reference to object type,
— a class member access expression designating a non-static data member of non-reference type in which the object expression is an xvalue, or [...]
—end note ]
std::move(a)
是对右值引用的强制转换,xvalue 也是如此。 std::move(a).m
是 xvalue 的 class 成员访问,xvalue 也是。
至于decltype(std::move(a).m)
。请注意,该词本身来自 declared type。 decltype(e)
含义的规则很复杂,来自 [dcl.type.simple]:
For an expression
e
, the type denoted bydecltype(e)
is defined as follows:
— ife
is an unparenthesized id-expression naming an lvalue or reference introduced from the identifier-list of a decomposition declaration,decltype(e)
is the referenced type as given in the specification of the decomposition declaration (8.5);
— otherwise, ife
is an unparenthesized id-expression or an unparenthesized class member access (5.2.5),decltype(e)
is the type of the entity named bye
. If there is no such entity, or ife
names a set of overloaded functions, the program is ill-formed;
— otherwise, ife
is an xvalue,decltype(e)
isT&&
, whereT
is the type ofe
;
— otherwise, ife
is an lvalue,decltype(e)
isT&
, whereT
is the type ofe
;
— otherwise,decltype(e)
is the type ofe
.
在这种情况下,我们有一个 class 成员访问权限,因此您只获得 m
的类型 - 即 M
而不是 M&&
。在某种程度上这是有道理的,您要求 m
的声明类型并且您得到了 m
的声明类型。
如果您想对其进行正确分类,可以使用一组额外的括号强制忽略该项目符号(显然):decltype((std::move(a).m))
会给您 M&&
.