c++ - 为什么在未计算的操作数中不允许使用 lambda 表达式,但在常量表达式的未计算部分中允许使用 lambda 表达式?

标签 c++ c++11 lambda c++14 constant-expression

如果我们查看 draft C++ standard 5.1.2 Lambda 表达式2 说(强调我的 future ):

The evaluation of a lambda-expression results in a prvalue temporary (12.2). This temporary is called the closure object. A lambda-expression shall not appear in an unevaluated operand (Clause 5). [ Note: A closure object behaves like a function object (20.8).—end note ]

5.19部分常量表达式2段说:

A conditional-expression is a core constant expression unless it involves one of the following as a potentially evaluated subexpression (3.2), but subexpressions of logical AND (5.14), logical OR (5.15), and conditional (5.16) operations that are not evaluated are not considered [...]

并有以下项目符号:

— a lambda-expression (5.1.2);

那么为什么 lambdas 表达式不允许在未计算的操作数中,但允许在常量表达式的未计算部分?

我可以看到在几种情况下( decltypetypeid )对于未计算的操作数,类型信息不是很有用,因为每个 lambda 都有一个唯一的类型。虽然我们为什么要在常量表达式的未计算上下文中允许它们尚不清楚,但也许是为了允许 SFINAE ?

最佳答案

未计算的操作数排除的核心原因在 C++ Standard Core Language Defect Reports and Accepted Issues #1607. Lambdas in template parameters 中进行了说明。它旨在澄清这一限制,并在 5.1.2 节中说明限制的意图是:

[...] avert the need to deal with them in function template signatures [...]

作为问题文档,当前的措辞实际上有一个漏洞,因为常量表达式允许它们在未评估的上下文中。但它并没有直接说明这种限制的理由。避免名称修改的愿望很突出,您可以推断,避免扩展 SFINAE 也是需要的,因为提议的决议试图加强限制,即使有几个可行的替代方案允许 SFINAE5.1.2段落2的修改版本如下:

A lambda-expression shall not appear in an unevaluated operand (Clause 5 [expr]), in a template-argument, in an alias-declaration, in a typedef declaration, or in the declaration of a function or function template outside its function body and default arguments [Note: The intention is to prevent lambdas from appearing in a signature —end note]. [Note: A closure object behaves like a function object (20.10 [function.objects]). —end note]

此提案已被接受,并在 N3936( see this answer for a link )

为了更明确地讨论避免将 lambdas 作为 未计算的操作数的基本原理。标题为 Rationale for lambda-expressions not being allowed in unevaluated contexts 的讨论关于 comp.lang.cpp.moderated Daniel Krügler 列出了三个原因:

  1. 可能的SFINAE极端扩展案例:

[...]The reason why they became excluded was due to exactly this extreme extension of sfinae cases (you were opening a Pandora box for the compiler)[...]

  1. 在许多情况下它只是无用的,因为每个 lambda 都有一个唯一的类型,给出的假设示例:

    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; });
    

    声明和调用中的 lambda 类型不同(根据定义),因此这是行不通的。

  2. Name mangling也成为一个问题,因为一旦您在函数签名中允许 lambda ,则 lambda 的主体也必须被破坏。这意味着要制定规则来破坏每一个可能的语句,这至少对某些实现来说是个负担。

关于c++ - 为什么在未计算的操作数中不允许使用 lambda 表达式,但在常量表达式的未计算部分中允许使用 lambda 表达式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22232164/

相关文章:

c++ - pthread_once() 中的竞争条件?

lambda - C++0x 闭包的未定义行为 : I

java - 什么是引导方法参数 - Java 字节码

c++ - 防止基于模板参数编译函数(或部分函数)

c++ - 如何使用 move 的对象?

c++ - 如果可能,取消对 C++ 类型指针的引用

通过静态声明启动时,Java lambda 陷入死锁

c++ - 优点和缺点内联 friend 助手免费功能在大型项目的类中定义

c++ - 函数调用运算符的继承和重载

c++ - 如何从邻接矩阵创建无向图?