c++ - 在嵌套 lambda 的情况下如何初始化 lambda 捕获?

标签 c++ c++11 lambda language-lawyer

好的,这就是 n3337.pdf 中 [expr.prim.lambda]p16 中的一招。下面以代码为例:

int a = 1, b = 1, c = 1;
auto m1 = [a, &b, &c]() mutable
{
    auto m2 = [a, b, &c]() mutable
    {
        std::cout << a << b << c;     // Shouldn't this print 113 or 133?
        a = 4; b = 4; c = 4;
    };
    a = 3; b = 3; c = 3;
    m2();
};
a = 2; b = 2; c = 2;
m1();
std::cout << a << b << c;             // Okay, this prints 234

并且它将生成以下输出:

123234



但是,按照我对 [expr.prim.lambda] 中文本的理解方式(这显然有缺陷),我觉得输出应该是 113234 ,特别是 b 的值印于 m2 .以下是我的理解/解释:

std::cout << a << b << c;m2 内执行,根据 [expr.prim.lambda]p16(强调我的):

If a lambda-expression m2 captures an entity and that entity is captured by an immediately enclosing lambda expression m1, then m2’s capture is transformed as follows:

if m1 captures the entity by copy, m2 captures the corresponding non-static data member of m1’s closure type;



因此,am2将生成的成员捕获到对应的a在闭包类型中捕获 m1 .自 am1按拷贝捕获,和 am2也通过拷贝捕获,a的值在 m2应该是 1 .

标准接着说(再次强调我的):

if m1 captures the entity by reference, m2 captures the same entity captured by m1.



我相信这里的“同一实体”是指m1捕获的实体。通过引用,当被 m2 捕获时它应该是 - 如果是按引用捕获,则是对同一实体的引用,如果是按拷贝捕获,则是对同一实体的引用。

因此对于 bm2应引用b在两个 lambda 表达式之外定义。 b的值在 m2那么应该是 1b也被复制捕获。

我哪里错了?更具体地说,什么时候是 bm2初始化?

最佳答案

首先,请注意,根据 C++11 [expr.prim.lambda] 第 14 段(或 C++17 [expr.prim.lambda.capture] paragraph 10),捕获是通过复制还是通过引用仅取决于 lambda 表达式自己的 lambda 引入器(初始 [] 部分)。

您从 C++11 [expr.prim.lambda]/16(或在 C++17 [expr.prim.lambda.capture]/13 中相同)引用的片段仅更改捕获的实体,而不更改捕获的实体类型捕获。因此,在示例中,用于初始化 m2 的内部 lambda 通过复制从原始定义中捕获 b

然后,请注意 C++11 [expr.prim.lambda]/21:

When the lambda-expression is evaluated, the entities that are captured by copy are used to direct-initialize each corresponding non-static data member of the resulting closure object.



(C++17 [expr.prim.lambda.capture]/15 开头相同,但为初始化捕获语法添加了额外的措辞,如 [var=init] 。)

在示例中,每次调用 m2 时,都会计算用于初始化 b 的内部 lambda 表达式,并初始化 m1.operator() 的闭包对象成员,而不是按照 lambda 表达式出现在代码中的顺序。由于 m2 的 lambda 通过复制捕获原始 b,因此它在调用 b 时获取 m1 的值。如果多次调用 m1,则 b 的初始值每次都可能不同。

关于c++ - 在嵌套 lambda 的情况下如何初始化 lambda 捕获?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62047185/

相关文章:

c++ - 圆形和矩形之间的碰撞

c++ - Play Scala - 原生访问

C++11 - move 包含文件流的对象

C++ 11 实现接口(interface)的方法不可用。为什么?

c# - 如何根据类型列表检查对象的类型?

c++ - 在 C++ 中输出分配给 double 组中的元素的字符串

C++ 约束 enable_if 与 requires

c++ - future::wait() 是否与 async() 执行线程的完成同步?

php - Lambda 函数索引

Java 8 使用流、flatMap 和 lambda