2017-07-06 83 views
11

如果我理解正确this answer和参考标准节[dcl.type.auto.deduct-5],代码:在decltype(auto)的情况下是否有lambda的特殊规则?

decltype(auto) a = e; 

总是等同于

decltype(e ) a = e; 

但现在的问题出现,如果不是的e我把lambda表达式decltype(auto)

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

本编译,令我惊讶的是,在gccclang都成功。原因我已经经历了震荡中奠定了标准,具体说是拉姆达不应该在未计算的操作数[expr.prim.lambda#2](重点煤矿)发生:

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

但正如我所提到的例子是等价于:

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

书面明确显然上面的代码会形成不良。当然我们可以假设decltype里面的语句[](){}是一种参考,并不像structured bindings那样是一个参考,但是在标准中有一个特殊规则,我错过了包括lambda初始化decltype(auto)

回答

7

这个答案是基于我对相关标准文本的解释。这些部分对分歧意见不是很清楚,因此目前很难知道它们的确切含义。看起来,除了可能的监督之外,主要的编纂者似乎都认为,有关的定义确实是完整的。

此外,我认为听到这个定义不合格会令人非常惊讶。


原因我所经历的震荡标准,说具体为拉姆达不应该在未计算的操作数出现[...]

奠定你在哪里看到出现一个lambda在未评估的情况下?

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

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

你的困惑可能来自大约是因为你似乎认为,上述说法是相当于

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

这不是的情况下,虽然严格来说。如果你看一下措辞的语言,有一个小的差异(由我高亮):

如果占位符是decltype(auto)类型说明符T应单独占位符。推导出的T的类型按照[dcl.type.simple]中的描述确定,因为尽管e已经成为decltype的操作数。

这里的关键词是,虽然。这仅表示扣除发生在decltype(e),这意味着decltype的扣除规则适用于操作数eauto的扣除规则。

这里,操作e的确是拉姆达,但这是完全合法的,因为标准授权行为就如同你会写decltype([](){})相同,这意味着的decltype扣除的规则适用于拉姆达。现在[expr.prim.lambda]/2在这里不适用,因为lambda不在未评估的上下文中,所以编译器使用decltype([](){})推断该类型实际上是合法的,这意味着必须使用decltype规则用于lambda。

当然,如果你写decltype([](){}),该程序是不合格的,但在这里不是这样,如上所述。

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

至少这就是我所理解它...

+0

好两种编译器团队独立理解像你这样有一个巨大的机会,你是对的。尽管如此,如果你说“它不完全等效”,那么不应该对如何解释它有严格的规定吗? –

+0

我的意思是 - 它不应该像初始化列表的情况下行事 - 其中'自动x6a = {1,2};'是好的,但'decltype(auto)x6d = {1,2};'不是? –

+1

@ W.F .:“*不应该有如何解释它的严格规定*”有一个严格的规则;他只是为你引用了它。这就是为什么“两个编译器团队”是对的。 –

相关问题