在decltype(auto)的情况下,lambda是否有特殊规则?

时间:2017-07-06 10:29:30

标签: c++ lambda c++14 language-lawyer decltype

如果我理解正确this answer并引用标准部分[dcl.type.auto.deduct-5],则代码为:

decltype(auto) a = e;

总是等同于

decltype( e  ) a = e;

但是现在问题出现了,而不是e我将lambda表达式放到decltype(auto)

decltype(auto) lambda = [](){};

令我惊讶的是,这在gccclang成功编译。我所经历过的冲击的原因在于标准,其中特别指出lambda不应出现在未评估的操作数[expr.prim.lambda#2]中(强调我的):

  

lambda-expression是一个prvalue,其结果对象称为   闭合对象。 lambda表达式不应出现在未评估的表达中   操作数,在模板参数中,在别名声明中,在typedef中   声明,或在函数或函数模板的声明中   在其函数体和默认参数之外。

但正如我所提到的,这个例子相当于:

decltype([](){}) lambda = [](){};

上面明确写出的代码显然是不正确的。当然,我们可以假设[](){}中的decltype语句是一种引用,并不像structured bindings那样真正引用,但也许有一个特殊规则我错过了覆盖lambda初始化decltype(auto)的标准?

1 个答案:

答案 0 :(得分:7)

这个答案是基于我对相关标准文本的解释。这些部分不是很明确,意见分歧,因此目前很难知道它们的确切含义。看来,除了可能的疏忽之外,主要的编制者似乎都同意所讨论的定义确实是格式良好的。

此外,我认为听到定义不明确是非常令人惊讶的。

  

我所经历的冲击的原因在于标准,其中特别指出lambda不应出现在未评估的操作数中[...]

在哪里看到lambda出现在未评估的背景中?

decltype(auto) lambda = [](){};

我没有看到它,因为没有。 lambda用作初始化器,这是完全合法的。

现在你的混乱可能是因为你似乎认为上述陈述等同于

decltype([](){}) lambda = [](){};

严格来说,情况并非如此。如果你看一下措辞的语言,就会有一点不同(由我强调):

  

如果占位符是decltype(auto) 类型说明符,则T应仅为占位符。 T推导出的类型按照[dcl.type.simple]中的描述确定,因为虽然 edecltype的操作数。

这里的关键词是虽然。这只是意味着扣除就像decltype(e)一样,这意味着decltype的扣除规则适用于操作数auto而不是e的扣除规则。

这里,操作数e确实是lambda,但这是完全合法的,因为标准规定行为是相同的,就好像你写的那样{{1} },意味着decltype([](){})演绎规则适用于lambda。现在decltype不适用于此,因为lambda不在未评估的上下文中,因此编译器使用[expr.prim.lambda]/2来推断类型实际上是合法的,这意味着decltype([](){})规则必须用于lambda。

当然,如果你写decltype,程序就是格式错误,但如上所述,情况并非如此。

在这种情况下,因为lambda表达式是prvalue,所推导出的类型应该只是lambda的类型。

至少我是这样理解的......