C++ decltype((A{}.int_成员))的正确结果是什么?

C++ decltype((A{}.int_成员))的正确结果是什么?,c++,c++14,language-lawyer,c++17,C++,C++14,Language Lawyer,C++17,给定类型A的定义: struct A { int i; }; 根据规范[expr.ref](我使用n4618): (如果E2为非参考,)…如果E1为左值,则E1.E2为左值;否则,E1.E2是一个x值 显然,A{}.i是xvalue; 还考虑到[dcl.type.simple]: (对于decltype(e),)-。。。如果e是未加密的id表达式或未加密的类成员访问。。。 -否则,如果e是一个x值,decltype(e)是T&&,其中T是e 因此,decltype((A{}.i))将产生int

给定类型
A
的定义:

struct A { int i; };
根据规范[expr.ref](我使用n4618):

(如果
E2
为非参考,)…如果
E1
为左值,则
E1.E2
为左值;否则,
E1.E2
是一个x值

显然,
A{}.i
是xvalue; 还考虑到[dcl.type.simple]:

(对于
decltype(e)
,)-。。。如果
e
是未加密的id表达式或未加密的类成员访问。。。 -否则,如果
e
是一个x值,decltype(e)是T&&,其中T是
e

因此,
decltype((A{}.i))
将产生int&


但是我尝试了GCC5.1和Clang3.9,它们产生int,而vs2015u3产生int&。哪个是正确的?

int&
是正确的


您在[expr.ref]中引用的措辞在几年前被更改,并且没有立即被实现采用;看看我的答案。基本上,编译器必须同时采用DR 616和关于临时表达式的论文,否则他们会破坏需要对象生命周期扩展的代码,在该扩展中,我们将引用绑定到对象的成员。在旧的实现模型中,只有prvalues可以指定生命期扩展可行的对象(尽管Johannes指出的措辞中不存在此类要求,N3918之前的措辞很模糊,所以…。

根据我的理解,我同意
int&
clangtrunk。n4618来自2016年底,不太可能是clang 3.9和gcc 5.1的一部分。@Nicolas No,IMO
std::move(a)
显然是一个xvalue,因此表达式显然也是一个xvalue。@skypjack我检查了我引用的措辞是否与c++14草稿中的相同。无论如何,您提供的铿锵主干符合草稿。@Nicolas,这不是dup:在这个问题中,对象表达式是一个xvalue,但在这里是一个prvalue,因此
move(a).m
始终是一个xvalue,但
a{}.int_成员
没有。“只有prvalue可以指定生命期扩展可行的对象”。我不同意,这似乎是一个常见的误解,IIRC。旧模型声明:“引用绑定到的临时对象或作为引用绑定到的子对象的完整对象的临时对象在引用的生存期内持续存在”,它不要求子对象用PR值表示。只是它是一个完整临时对象的子对象。你能为我澄清一下吗?链接的回答说“现状是只有prvalues被视为临时值”,这是当时的xvalue不再延长寿命的原因:你似乎在说“Foo().bar”在某个时候是临时值,因为它是prvalue,但将其更改为xvalue使其成为非临时性的。但我认为规范不支持这一点。它说“Foo()”是一个临时对象,因为我们将它的子对象(不是临时对象)绑定到一个引用,所以临时完整对象的生命周期延长了。@johanneschaub litb IIRC。不管怎么说,我在飞行中起草了这个答案,但请注意,我从来没有提到过措辞,我只提到了供应商所做的事情。我加了一张便条让它更清楚。无论如何,谢谢你指出这一点!我还不清楚这个问题是如何在标准中解决的。。。C++14包含“否则E1.E2是一个xvalue…”但不包含“临时表达式”一词,那么这是否意味着C++14文本没有指定绑定到成员的生存期扩展?我在N4606中也没有看到“临时表达”的措辞。C++17是要采用“临时表达式”之类的东西,还是要用另一种方式解决问题?@M.M总是查看最新的草稿:)