#include <iostream>
#include <type_traits>
struct A { double x; };
int main()
{
const A && a1 = A();
std::cout << std::is_same_v<decltype((a1.x)), const double&>;
std::cout << std::is_same_v<decltype((std::move(a1).x)), const double&&>;
std::cout << std::is_same_v<decltype((A().x)), double>;
}
Output:
111
上一个示例中的decltype 不应返回double&&,因为根据value categories . A().x 是一个xvalue
xvalue
a.m, the member of object expression, where a is an rvalue and m is a non-static data member of non-reference type;
...
在 en.cppreference.com/w/cpp/language/decltype 的代码片段中使用 gcc7.1;gcc5.2;clang3.8;gcc4.9;gcc4.8;gcc4.7 测试
最佳答案
严格按照标准,看来你是对的,应该是 double &&
。我的推理链(所有引用自 C++17 (n4659)):
8.2.5 类成员访问[expr.ref]
1 A postfix expression followed by a dot
.
or an arrow->
, optionally followed by the keywordtemplate
(17.2), and then followed by an id-expression, is a postfix expression. ...2 For the first option (dot) the first expression shall be a glvalue having complete class type.
3 Abbreviating postfix-expression.id-expression as
E1.E2
,E1
is called the object expression. ... The type and value category ofE1.E2
are determined as follows. In the remainder of 8.2.5, cq represents eitherconst
or the absence ofconst
and vq represents eithervolatile
or the absence ofvolatile
. cv represents an arbitrary set of cv-qualifiers, as defined in 6.9.3....
(4.2) If
E2
is a non-static data member and the type ofE1
is “cq1 vq1X
”, and the type ofE2
is “cq2 vq2T
”, the expression designates the named member of the object designated by the first expression. IfE1
is an lvalue, thenE1.E2
is an lvalue; otherwiseE1.E2
is an xvalue. ...
因此,如果 .
的左侧操作数是一个 xvalue,那么整个 .
表达式的结果也是一个 xvalue。
8.2.3 显式类型转换(函数符号)[expr.type.conv]
1 A simple-type-specifier (10.1.7.2) or typename-specifier (17.6) followed by a parenthesized optional expression-list or by a braced-init-list (the initializer) constructs a value of the specified type given the initializer. ...
2 ... the expression is a prvalue of the specified type whose result object is direct-initialized (11.6) with the initializer.
所以 A()
是一个纯右值。
最后:
8 表达式 [expr]
10 Whenever a prvalue expression appears as an operand of an operator that expects a glvalue for that operand, the temporary materialization conversion (7.4) is applied to convert the expression to an xvalue.
综合起来,这意味着 A()
是一个纯右值(来自 8.2.3/2)。由于 .
要求其 LHS 操作数是一个 glvalue,因此应用了临时物化转换(每 8/10),结果是一个 xvalue。因此,从 8.2.5/(4.2) 开始,由于 E1
是一个 xvalue,因此 E1.E2
也是一个 xvalue,即 A().x
在你的情况下。
至于decltype
:
10.1.7.2 简单类型说明符[dcl.type.simple]
4 For an expression
e
, the type denoted bydecltype(e)
is defined as follows:...
(4.3) ... if
e
is an xvalue,decltype(e)
isT&&
, whereT
is the type ofe
;
因为在你的例子中,(A().x)
被确定为一个 xvalue,它的 dectlype
应该是 double &&
。
关于c++ - 物化纯右值成员访问的 decltype 行为不正确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50366460/