#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不应该在最后一个例子中解密返回double& last,根据价值范畴的说法。A().x是一个xvalue
X值 a.m,对象表达式的成员,其中a是rvalue,m是非引用类型的非静态数据成员; ..。
用gcc7.1;gcc5.2;clang3.8;gcc4.9;gcc4.8;gcc4.7在en.cppreference.com/w/cpp/language/decltype的代码片段中进行测试
发布于 2018-05-16 09:18:35
严格按照标准,你似乎是对的,而且应该是double &&。我的推理链(来自C++17 (N4659)的所有引号):
8.2.5类成员访问expr.ref
1后缀表达式后面跟着点
.或箭头->,可选地后面跟着关键字template(17.2),然后是id表达式,是后缀表达式。..。 2对于第一个选项(点),第一个表达式应为具有完整类类型的glvalue。 3缩写后缀表达式. is表达式为E1.E2,E1称为对象表达式。..。E1.E2的类型和值类别确定如下。在其余的8.2.5中,cq表示const或const的缺失,vq表示volatile或volatile的缺失。cv表示6.9.3中定义的任意一组cv-限定符。 ..。 (4.2)如果E2是非静态数据成员,而E1的类型是“cq1 vq1X”,而E2的类型是“cq2 vq2T”,则表达式指定第一个表达式指定的对象的命名成员。如果E1是lvalue,那么E1.E2是lvalue;否则E1.E2是xvalue。..。
因此,如果.的左侧操作数是xvalue,则整个.表达式的结果也是如此。
8.2.3显式类型转换(函数表示法) expr.type.conv
1一个简单类型说明符(10.1.7.2)或类型名称说明符(17.6),后面跟着一个括号大小的可选表达式-列表,或者由一个带括号的-init-列表(初始化程序)构造指定类型的值。..。 2...表达式是指定类型的prvalue,其结果对象与初始化器直接初始化(11.6)。
因此,A()是一个prvalue。
最后:
8词组费用
10每当一个prvalue表达式显示为一个操作符的操作数时,就会应用临时物化转换(7.4)将该表达式转换为xvalue。
综合起来,这意味着A()是一个prvalue (来自8.2.3/2)。因为.要求它的LHS操作数是一个glvalue,所以临时物化转换是附加的( 8/10),结果是xvalue。因此,从8.2.5/(4.2)开始,因为E1是一个xvalue,所以E1.E2也是,在您的例子中是A().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 &&。
https://stackoverflow.com/questions/50366460
复制相似问题