【问题标题】:What is the correct result of decltype( (A{}.int_member) )?decltype( (A{}.int_member) ) 的正确结果是什么?
【发布时间】:2017-02-04 07:20:21
【问题描述】:

给定类型A的定义:

struct A { int i; };

根据规范[expr.ref](我用的是n4618):

(如果E2 是非引用,) ...如果E1 是左值,那么E1.E2 是左值;否则 E1.E2 是一个 xvalue...

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

(for decltype(e),) — ... 如果e 是一个无括号 id 表达式或一个无括号 类成员访问... — 否则,如果e是一个xvalue,decltype(e)是T&&,其中T是e的类型 p>

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

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

【问题讨论】:

  • 根据我的阅读方式,我同意int &&
  • clang 主干works as expected。 n4618 来自 2016 年底,不太可能是 clang 3.9 和 gcc 5.1 的一部分。
  • @NicolBolas 不,IMO std::move(a) 显然是一个 xvalue,因此表达式显然也是一个 xvalue。
  • @skypjack 我检查了我引用的措辞是否与 c++14 草案中的相同。无论如何,您提供的 clang 后备箱符合草稿要求。
  • @NicolBolas 这不是一个重复:对象表达式在那个问题中是一个 xvalue,但在这里是一个prvalue,所以move(a).m 一直是一个 xvalue,但A{}.int_member 不是。

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


【解决方案1】:

int&& 是正确的。

您在 [expr.ref] 中引用的措辞在几年前被 cwg 616 更改,并没有立即被实现采用;看我的回答here。基本上,编译器必须同时采用 DR 616 和关于临时表达式的论文,否则他们会破坏需要对象生命周期扩展的代码,我们将引用绑定到对象的 member。在旧的实现模型中,只有纯右值可以指定可以延长生命周期的对象(尽管 Johannes 指出的措辞中不存在这样的要求,但在 N3918 之前它是模糊的措辞,所以……)。

【讨论】:

  • “只有纯右值可以指定生命周期延长可行的对象”。我不同意,这似乎是一个普遍的误解,IIRC。旧模型指出:“引用绑定到的临时对象或引用绑定到的子对象的完整对象的临时对象在引用的生命周期内持续存在”,它不要求子对象表示为prvalue。只是它是一个完整的临时对象的子对象。你能帮我澄清一下吗?
  • 链接的答案指出“现状是只有纯右值被视为指代临时值”作为 then-xvalue 不再延长生命周期的原因:您似乎在说“Foo( ).bar" 在某些时候是临时的,因为它是一个纯右值,但是将其更改为 xvalue 使其成为非临时的。但我认为规范不支持这一点。它说“Foo()”是一个临时对象,并且因为我们将它的一个子对象(不是临时对象)绑定到一个引用,所以临时的完整对象是生命周期延长的。
  • @JohannesSchaub-litb IIRC prvalue-ness was an implicit requirement that implementers followed。无论如何,我草拟了这个答案,但请注意,我从未提到过措辞,我只提到了供应商所做的事情。我添加了一个小注释以使其更清晰。无论如何,感谢您指出这一点!
  • 我仍然不清楚标准中问题是如何解决的... C++14 包含“否则 E1.E2 是一个 xvalue...”但不包含“临时”字样表达式”,那么这是否意味着 C++14 文本没有指定绑定到成员的生命周期延长?我也没有在 N4606 中看到“临时表达”的措辞。 C++17 会采用“临时表达式”的东西,还是会以另一种方式解决问题?
  • @M.M 总是查看最新的草稿 :)
猜你喜欢
  • 2013-02-09
  • 1970-01-01
  • 2021-12-23
  • 1970-01-01
  • 2019-12-18
  • 2022-12-07
  • 1970-01-01
  • 1970-01-01
  • 2016-08-14
相关资源
最近更新 更多