材料化 prvalues 的成员访问的 decltype 行为不正确。

3
#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

在最后一个例子中,根据值类别A().x 是一个 xvalue,因此 decltype 不应该返回 double&&

xvalue

a.m,即对象表达式的成员,其中 a 是 rvalue,m 是非引用类型的非静态数据成员;

...

在 en.cppreference.com/w/cpp/language/decltype 的代码片段中测试过 gcc7.1、gcc5.2、clang3.8、gcc4.9、gcc4.8 和 gcc4.7。

我使用 clang7 得到了 "110"。 - songyuanyao
我使用gcc 7.1、gcc 5.2、clang 3.8、gcc 4.9、gcc 4.8和gcc 4.7,得到了111。 - mkmostafa
我正在测试http://en.cppreference.com/w/cpp/language/decltype代码片段页面中提供的编译器。 - mkmostafa
无论如何,我认为类型应该是double&&,除非cppreference.com错了... - songyuanyao
1个回答

1

按照标准,看起来你是正确的,应该使用 double &&。我的推理链条(所有引用都来自 C++17 (n4659)):

8.2.5 类成员访问 [expr.ref]

1 后缀表达式后跟一个点 . 或箭头 ->,可选择跟关键字 template (17.2),然后跟着一个 id-expression,是一种后缀表达式。...

2 对于第一个选项(点),第一个表达式应为具有完整类类型的glvalue。

3 将postfix-expression.id-expression缩写为E1.E2,其中E1称为object expression。 ... E1.E2的类型和值类别如下确定。在8.2.5的其余部分中,cq表示const或缺少constvq表示volatile或缺少volatilecv表示一组任意的cv限定符,如6.9.3所定义。

...

(4.2) 如果E2是非静态数据成员,并且E1的类型为“cq1 vq1 X”,E2的类型为“cq2 vq2 T”,则该表达式指定由第一个表达式指定的对象的命名成员。如果E1是一个lvalue,则E1.E2是一个lvalue;否则,E1.E2是一个xvalue。...

如果.左侧操作数是xvalue,那么整个.表达式的结果也是xvalue。
8.2.3 显式类型转换(函数表示法)[expr.type.conv]
1 简单类型说明符(10.1.7.2)或类名说明符(17.6)后跟一个带括号的可选表达式列表或一个大括号初始化列表(初始值设定项)根据初始值构造指定类型的值。...
2 ...表达式是指定类型的prvalue,其结果对象用初始值进行直接初始化(11.6)。
因此,A()是prvalue。
最后:
8 表达式 [expr]
10 每当prvalue表达式出现为预期该操作数的glvalue的运算符的操作数时,临时物化转换(7.4)被应用于将表达式转换为xvalue。
综上所述,这意味着A()是一个prvalue(来自8.2.3/2)。由于.要求其左操作数为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 对于表达式e,由decltype(e)表示的类型定义如下:

...

(4.3) ...如果e是一个xvalue,则decltype(e)T&&,其中Te的类型;

在您的情况下,(A().x) 被确定为 xvalue,因此它的 dectlype 应该是 double &&

我在这里 http://en.cppreference.com/w/cpp/language/operator_member_access#Built-in_member_access_operators 和 http://en.cppreference.com/w/cpp/language/implicit_conversion#Temporary_materialization 得出了相同的结论。 - mkmostafa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接