为什么Lambda表达式不允许在未求值操作数中,但允许在常量表达式的未求值部分中?

20
如果我们查看草案C++标准中的第5.1.2节 Lambda表达式第2段说(强调我将向前):
引入lambda表达式将产生一个prvalue临时对象(12.2)。这个临时对象称为闭包对象。 lambda表达式不得出现在未评估的操作数中(第5条)。[注意:闭包对象的行为类似于函数对象(20.8)。-注释]
并且第5.19节常量表达式第2段说:
条件表达式是核心常量表达式,除非它涉及以下之一作为潜在评估的子表达式(3.2),但未评估的逻辑AND(5.14),逻辑OR(5.15)和条件(5.16)操作的子表达式不予考虑[...]
并具有以下要点:

— 一个lambda表达式(5.1.2);

那么为什么lambda表达式不允许在未求值的操作数中使用,但是可以在常量表达式的未求值部分中使用呢?

我能看出来,在几种情况下(decltypetypeid),未求值操作数中的类型信息并不是很有用,因为每个lambda都有唯一的类型。虽然为什么我们想要允许它们在常量表达式的未求值上下文中使用还不清楚,也许是为了允许SFINAE?

1个回答

24
核心原因是C++标准核心语言缺陷报告和已接受问题#1607. 模板参数中的Lambda所涵盖的未评估操作数排除,该报告旨在澄清这一限制,并在第5.1.2节中说明了该限制的意图:

[...] 避免在函数模板签名中处理它们 [...]

正如该问题记录的那样,当前措辞实际上存在漏洞,因为常量表达式允许它们在未评估的上下文中使用。但它并没有直接说明这个限制的理由。避免名称重整的愿望非常突出,您可以推断出避免扩展SFINAE也是期望的,因为所提议的解决方案试图加强这一限制,即使有几种可行的替代方案也可以允许SFINAE。修改后的5.1.2段落2如下:

一个lambda表达式不得出现在未求值的操作数(第5条[expr]),模板参数,别名声明,typedef声明或函数或函数模板的声明之外的函数体和默认参数中[注:意图是防止lambda出现在签名中 - 结束注释]。[注:闭包对象的行为类似于函数对象(20.10 [function.objects])。-结束注释]
该提案已被接受,并收录于N3936中(请参见此答案的链接)。
有关避免将lambda用作未求值操作数的原因的更明确讨论,请查看comp.lang.cpp.moderated上标题为Rationale for lambda-expressions not being allowed in unevaluated contexts的讨论,Daniel Krügler列出了三个原因:
  1. 可能的SFINAE情况的极端扩展:

[...]它们被排除的原因正是由于SFINAE情况的极端扩展(你为编译器打开了一个潘多拉魔盒)[...]

  1. In many cases it is just useless since each lambda has a unique type, the hypothetical example given:

    template<typename T, typename U>
    void g(T, U, decltype([](T x, T y) { return x + y; }) func);
    
    g(1, 2, [](int x, int y) { return x + y; });
    

    The type of the lambda in the declaration and the call are different(by definition) and therefore this can not work.

  2. Name mangling also becomes a problem since once you allow a lambda in a function signature the bodies of the lambda will have to be mangled as well. This means coming up with rules to mangle every possible statement, which would burdensome for at least some implementations.


n3936 似乎已经被密码保护(fdis?),链接也失效了。 - dyp
@dyp 嗯,今天早上还可以用,算了。Loki也在这里提到了它,所以可能只是暂时的,我看看能不能弄清楚发生了什么。 - Shafik Yaghmour
我认为现在它已经是一个FDIS了。http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/ 上的新链接表明了这一点:http://www.open-std.org/jtc1/sc22/wg21/prot/14882fdis/n3936.pdf - dyp
请参阅 D0315R2 - Shafik Yaghmour
2
看起来p0315r3已经被C++20接受了。 - Shafik Yaghmour

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接