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



如果我正确理解了这个答案并引用了标准部分[dcl.type.auto.deduct-5],代码:

decltype(auto) a = e;

始终等效于

decltype( e  ) a = e;

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

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

令我惊讶的是,这在 gcc 和 clang 中都成功编译。我所经历的冲击的原因在于标准,它特别指出lambda不应该出现在未计算的操作数[expr.prim.lambda#2]中(强调我的(:

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

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

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

上面明确编写的代码显然是格式不正确的。当然,我们可以假设decltype内部[](){}语句是一种引用,不像结构化绑定那样真正是引用,但也许标准中有一个特殊的规则,我错过了涵盖 lambda 初始化decltype(auto)

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

此外,我认为,听到定义格式不正确会非常令人惊讶。


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

您在哪里看到 lambda 出现在未计算的上下文中?

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

我没有看到它,因为没有。lambda 用作初始值设定项,这是完全合法的。

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

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

但严格来说,情况并非如此。如果你看一下措辞的语言,有一个很小的差异(由我强调(:

如果占位符是decltype(auto)类型说明符,则T应单独占位符。为T推导的类型是按照 [dcl.type.simple] 中所述确定的,就好像edecltype的操作数一样。

不过,这里的关键词是。它只是意味着扣除就像decltype(e)一样发生,这意味着decltype的扣除规则适用,而不是操作数eauto规则。

在这里,操作数e确实是lambda,但这是完全合法的,因为标准要求行为与你写decltype([](){})相同,这意味着decltype导规则适用于lambda。现在[expr.prim.lambda]/2在这里不适用,因为 lambda 不在未计算的上下文中,因此编译器使用decltype([](){})来推断类型实际上是合法的,这意味着必须将decltype规则用于 lambda。

当然,如果你写decltype([](){}),程序格式不正确,但如上所述,这里的情况并非如此。

在这种情况下,由于 lambda 表达式是 prvalue,因此推导的类型应该只是 lambda 的类型。

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

最新更新