C++ Standard Core Language Defect Reports and Accepted Issues #1607中介绍了未评估操作数排除的核心原因。模板参数中的 Lambda 旨在澄清此限制并在部分中说明限制的意图5.1.2
是:
[...] 无需在函数模板签名中处理它们 [...]
作为问题文档,当前的措辞实际上有一个漏洞,因为常量表达式允许它们在未评估的上下文中。但它并没有直接说明这种限制的理由。避免名称修改的愿望很突出,您可以推断,避免扩展SFINAE也是需要的,因为提议的决议试图加强限制,即使有几个可行的替代方案允许SFINAE。5.1.2
第2段的修改版本如下:
lambda 表达式不得出现在未计算的操作数(第 5 条 [expr])、模板参数、别名声明、typedef 声明或函数体之外的函数或函数模板的声明中和默认参数 [注意:目的是防止 lambdas 出现在签名中——结束注释]。[注意:闭包对象的行为类似于函数对象(20.10 [function.objects])。——尾注]
该提案已被接受并在N3936
(请参阅此答案以获取链接)
更明确地讨论避免将 lambdas 作为未计算的操作数的基本原理。comp.lang.cpp.moderated Daniel Krügler上题为lambda-expressions not allowed in unevaluate contexts的讨论提出了三个原因:
- 可能的SFINAE案例的极端扩展:
[...]它们被排除在外的原因正是由于 sfinae 案例的这种极端扩展(您正在为编译器打开一个潘多拉盒子)[...]
在许多情况下,它只是无用的,因为每个 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 类型不同(根据定义),因此这是行不通的。
名称修改也成为一个问题,因为一旦您在函数签名中允许使用lambda ,则lambda的主体也必须被修改。这意味着要制定规则来破坏每一个可能的语句,这对于至少某些实现来说是很麻烦的。