为什么捕获lambda在C++中不起作用?

我正在使用 C++ 中的 lambda 表达式,我尝试了一些方法来查看结果。我实际上在 CppCon Back to Basics: Lambdas from Scratch - Arthur O'Dwyer - CppCon 2019 @21:47 中观看了视频并开始使用 lambdas。

举个例子,我试过这个:

#include <iostream>
using namespace std;
int g = 10;//global var 'g'

//creating lambda
auto kitten = [=] () {return g+1;};
auto cat = [g=g] () {return g+1;};
// main
int main()
{
    g = 20;//modifying global variable 'g'
    cout<<"kitten: "<<kitten()<<"cat: "<<cat()<<endl;

    return 0;
}

上面代码的输出是:

kitten: 21cat: 11

在上面的例子中:[g=g]表示捕获一个名称g和类型与外部相同的数据成员g,就像我写的一样auto g=g。这是一个副本g。当我们认为(就像我以 的形式编写auto g=g)时,这是有道理的,因此在我们的例子中结果是 11,其中全局的修改g没有反映在我们的local g.

小猫的结果是 21,因为据我所知,捕获所有内容,即按值捕获所有外部变量。

然后,当涉及到这个例子时,通过修改第一个 lambda 如下:

auto kitten = [] () {int g  = g; return g+1;};
auto kitten = [] () {int g  = g; return g+1;};

local g从声明并赋值的地方global g,输出是:

kitten: 1cat: 11

但是我期待第一个示例 (21) 中的输出,因为我正在尝试创建一个 localg并从 global 分配它的值g,它已经是修改后的值 20。

代码在https://techiedelight.com/compiler/和 Godbolt.org 上使用 c++ (GCC 8.3.0) 编译(使用最新的编译器,[=]这是不允许的,但结果是一样的)。

此刻,我对捕获和/或 lambda 的概念有些困惑。

回答

auto kitten = [=] () {return g+1;}

这个 lambda 根本不捕获任何东西。几乎和刚才一样

int kitten() { return g+1; }

只能捕获局部变量,在kitten定义范围内没有可见的局部变量。请注意,[=]或者[&]不是“捕获所有内容”,它们的意思是“捕获任何必要的东西”,并且在 lambda 中永远不需要(或不可能)捕获全局变量,因为该变量名称的含义始终相同当评估 lambda 主体时。


auto cat = [g=g] () {return g+1;}

这是一个init-capture,类似于创建一个局部变量并立即捕获它。该g等号之前声明的init-拍摄,并且g等号指定后如何初始化它。与大多数声明符(见下文)不同,g这里创建的变量不在其自己的初始化程序的范围内,因此g等号后面的表示全局变量::g。所以代码类似于:

auto make_cat()
{
    int & g = ::g;
    return [g]() { return g+1; }
}
auto cat = make_cat();

auto kitten = [] () {int g  = g; return g+1;}

这段代码有一个与 lambdas 无关的错误。在局部变量定义中int g = g;,等号之前声明的变量在等号之后的初始化期间在范围内。Sog是用它自己的不确定值初始化的。给那个不确定的值加一个是未定义的行为,所以结果是不可预测的。


回答

你在这里根本没有使用全局。您正在使用 localg来初始化 local g。程序的行为是未定义的。

为什么int g = g;要自己初始化本地 g,

因为初始化器在g声明本地的点之后。

那个编译器不应该用全局 g 初始化吗?

不。

  • 也许提出如何解决全局问题的建议:`auto kitten = [] () {int g = ::g; 返回 g+1;};`

以上是为什么捕获lambda在C++中不起作用?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>