首页 > 解决方案 > 物化纯右值成员访问的 decltype 行为不正确

问题描述

#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 categoriesA().x是一个xvalue

极值

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

...

在 en.cppreference.com/w/cpp/language/decltype 的代码片段中使用 gcc7.1;gcc5.2;clang3.8;gcc4.9;gcc4.8;gcc4.7 测试

标签: c++language-lawyerc++17

解决方案


严格按照标准,看来你是对的,应该是double &&。我的推理链(所有引用来自 C++17 (n4659)):

8.2.5 类成员访问 [expr.ref]

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

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

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

...

(4.2) ifE2是非静态数据成员,类型E1为“<em>cq1 vq1 X”,类型E2为“<em>cq2 vq2 T”,表达式指定第一个指定的对象的命名成员表达。如果E1是左值,那么E1.E2是左值;否则E1.E2是一个 xvalue。...

因此,如果 的左侧操作数.是一个 xvalue,那么整个.表达式的结果也是如此。

8.2.3 显式类型转换(函数表示法)[expr.type.conv]

1 一个简单类型说明符(10.1.7.2) 或类型名称说明(17.6) 后跟一个带括号的可选表达式列表 或一个花括号初始化列表(初始化器)构造一个给定初始化器的指定类型的值。...

2 ...表达式是指定类型的纯右值,其结果对象使用初始化程序直接初始化(11.6)。

A()prvalue也是如此。

最后:

8 个表达式 [expr]

10 每当一个纯右值表达式作为一个操作数的操作数出现时,该操作数需要一个左值,临时实现转换 (7.4) 用于将该表达式转换为一个 xvalue。

总之,这意味着这A()是一个prvalue(来自8.2.3 / 2)。由于.要求其 LHS 操作数是一个泛左值,因此应用了临时实现转换(每 8/10),结果是一个 xvalue。所以,从 8.2.5/(4.2) 开始,因为E1是一个 xvalue,所以是E1.E2A().x在你的情况下。

至于decltype

10.1.7.2 简单类型说明符 [dcl.type.simple]

4 对于表达式e,由 表示的类型decltype(e)定义如下:

...

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

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


推荐阅读