c++ - 物化纯右值成员访问的 decltype 行为不正确

标签 c++ language-lawyer c++17

#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 keyword template (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 of E1.E2 are determined as follows. In the remainder of 8.2.5, cq represents either const or the absence of const and vq represents either volatile or the absence of volatile. 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 of E1 is “cq1 vq1 X”, and the type of E2 is “cq2 vq2 T”, the expression designates the named member of the object designated by the first expression. If E1 is an lvalue, then E1.E2 is an lvalue; otherwise E1.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 by decltype(e) is defined as follows:

...

(4.3) ... if e is an xvalue, decltype(e) is T&&, where T is the type of e;

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

关于c++ - 物化纯右值成员访问的 decltype 行为不正确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50366460/

相关文章:

C++ "forgetting"该变量在用作函数参数时是 constexpr

c++ - C++读取大文件

c++ - 如何在进入循环之前选择在嵌套循环内调用的函数?

c++ - destroy_at/构造不可复制的 vector 元素有多大风险?

c++ - 为什么允许将派生类的方法静态转换为基类的方法?

c - "producing negative zeroes"在不支持的系统中是什么意思?

c++ - 隐式转换运算符 vs 模板构造函数——应该优先考虑谁?

c++ - 所有 const 标记方法都隐式 [[nodiscard]] 吗?

c++ - 在CHtmlEditCtrl中绘制 "red squiggly line"

c++ - 如何在虚类方法中使用 std::vector::remove()?