当前位置: 首页 > 知识库问答 >
问题:

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

苗运珧
2023-03-14

如果我们看一下C标准草案第5.1.2节,第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);

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

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

共有1个答案

令狐珂
2023-03-14

C标准核心语言缺陷报告和接受的问题#1607中介绍了未评估操作数排除的核心原因。模板参数中的Lambdas旨在澄清此限制,并在5.1.2节中说明限制的意图是:

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

由于问题记录了当前的措辞,实际上有一个漏洞,因为常量表达式允许它们在未评估的上下文中使用。但它没有明确说明这种限制的理由。避免名称混乱的愿望很突出,你可以推断,避免延长SFINAE也是需要的,因为提议的决议寻求收紧限制,即使有几个可行的替代方案会允许SFINAE。5.1.2第2段的修改版本如下:

lambda表达式不得出现在未计算的操作数(第5条[exr])、模板参数、别名声明、typedef声明或函数或函数模板在其函数体和默认参数之外的声明中[注意:目的是防止lambda出现在签名中-结束注释]。[注意:闭包html" target="_blank">对象的行为类似于函数对象(20.10[function.objects])。-结束注释]

该提案已被接受,并在N3936中(有关链接,请参阅此答案)

以更明确地讨论避免将lambda作为未赋值操作数的原理。讨论题为“lambda表达式在comp上未经评估的上下文中不被允许的理由”。lang.cpp。主持人丹尼尔·克鲁格勒列举了三个原因:

  1. 可能的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的主体也必须损坏。这意味着制定规则来破坏每一条可能的语句,这至少会给某些实现带来负担。

 类似资料:
  • 问题内容: 最近我遇到了一个问题:赋值运算符链理解。 在回答这个问题,我开始怀疑我自己的加法赋值运算符的行为的理解或任何其他(,,等)。 我的问题是,下面的表达式中的变量何时更新到位,以便其更改的值在求值过程中反映在表达式的其他位置,其背后的逻辑是什么?请看以下两个表达式: 表达式1 表达式2 在第一个表达式中,当计算最里面的表达式时,似乎不更新的值,因此结果是而不是。 但是,在第二个表达式中,的

  • 最近我遇到了这样一个问题:作业操作员链理解。 在回答这个问题时,我开始怀疑自己对加法赋值运算符或任何其他(

  • (译注:目前支持lambda的gcc编译器版本为4.5,其它详细的编译器对于C++11新特性的支持请参考http://wiki.apache.org/stdcxx/C%2B%2B0xCompilerSupport) Lambda表达式是一种描述函数对象的机制,它的主要应用是描述某些具有简单行为的函数(译注:Lambda表达式也可以称为匿名函数,具有复杂行为的函数可以采用命名函数对象,当然,何谓复杂

  • PEP 572引入了为Python 3.8实现的赋值表达式(俗称Walrus操作符)。这似乎是一个非常重要的新特性,因为它将允许在理解和lambda函数中进行这种形式的赋值。 赋值表达式的语法、语义学和语法规范到底是什么? 为什么在PEP 379中关于“添加赋值表达式”的类似想法之前遭到拒绝的情况下,引入了这个新的(似乎相当激进的概念)?

  • 我知道使用lambda expression(LE)我们可以节省一些代码行,比如为函数接口创建对象。而且LE将更易读。但我确信这并不是提供该功能的主要原因。我在google上搜索,并在本文中找到了这段有趣的引用 在Java8之前,处理任何集合的元素都可以通过从集合中获取迭代器,然后迭代元素,然后处理每个元素来完成。如果需要并行处理这些元素,那么将由客户端代码完成。随着Java 8中Stream A