gpt4 book ai didi

c++ - 为什么有时不需要在 lambda 中捕获 const 变量?

转载 作者:IT老高 更新时间:2023-10-28 12:09:23 26 4
gpt4 key购买 nike

考虑以下示例:

#include <cstdlib>

int main() {
const int m = 42;
[] { m; }(); // OK

const int n = std::rand();
[] { n; }(); // error: 'n' is not captured
}

为什么我需要在第二个 lambda 中捕获 n 而不是在第一个 lambda 中捕获 m?我检查了 C++14 标准中的第 5.1.2 节(Lambda 表达式),但找不到原因。你能指出一个解释这一点的段落吗?

更新:我在 GCC 6.3.1 和 7(主干)中都观察到了这种行为。 Clang 4.0 和 5(主干)在两种情况下都失败并出现错误(无法在未指定捕获默认值的 lambda 中隐式捕获变量“m”)。

最佳答案

对于 block 作用域的 lambda,满足到达作用域中某些条件的变量可以在 lambda 内以有限的方式使用,即使它们没有被捕获。

粗略地说,到达作用域包括包含 lambda 的函数的任何局部变量,该变量将在定义 lambda 时的作用域内。所以这包括上面例子中的mn

“某些标准”和“有限方式”具体是(从 C++14 开始):

  • 在 lambda 内部,变量不能是 odr-used,这意味着它不能进行任何操作,除了:
    • 显示为废弃值表达式(m; 是其中之一),或
    • 检索其值。
  • 变量必须是:
    • 一个 const、非volatile 整数或枚举,其初始值设定项为常量表达式,或
    • 一个constexpr,非volatile变量(或此类的子对象)

对 C++14 的引用:[expr.const]/2.7、[basic.def.odr]/3(第一句)、[expr.prim.lambda]/12、[expr.prim.lambda]/10.

正如其他评论/答案所建议的,这些规则的基本原理是编译器需要能够“合成”一个非捕获 lambda 作为独立于 block 的自由函数(因为这些东西可以转换为指向函数的指针);如果它知道变量总是具有相同的值,它可以尽管引用变量来执行此操作,或者它可以重复该过程以获得独立于上下文的变量的值。但如果变量有时可能不同,或者例如需要变量的地址,它就不能这样做。


在您的代码中,n 由非常量表达式初始化。因此 n 不能在没有被捕获的情况下在 lambda 中使用。

m 由常量表达式 42 初始化,因此它确实符合“某些标准”。丢弃值表达式不使用该表达式,因此可以使用 m; 而不捕获 m。 gcc 是正确的。


我会说这两个编译器之间的区别在于clang认为m;是odr-use m,但gcc没有。 [basic.def.odr]/3 的第一句相当复杂:

A variable x whose name appears as a potentially-evaluated expression ex is odr-used by ex unless applying the lvalue-to-rvalue conversion to x yields a constant expression that does not invoke any non-trivial functions and, if x is an object, ex is an element of the set of potential results of an expression e, where either the lvalue-to-rvalue conversion is applied to e, or e is a discarded-value expression.

但仔细阅读后,它确实特别提到了丢弃值表达式不odr-use该表达式。

C++11 版本的 [basic.def.odr] 原本不包括丢弃值表达式的情况,因此在已发布的 C++11 下,clang 的行为是正确的。然而,出现在 C++14 中的文本被认为是针对 C++11 的缺陷 (Issue 712),因此编译器即使在 C++11 模式下也应该更新它们的行为。

关于c++ - 为什么有时不需要在 lambda 中捕获 const 变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43467095/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com