为什么捕获 lambda 在 C++ 中不起作用?
Why capture lambda does not working in 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
的修改没有反映在我们的 [=21 中=].
小猫的结果是 21 因为据我所知,捕获所有内容,即按值捕获所有外部变量。
然后,当涉及到这个例子时,修改第一个lambda如下:
auto kitten = [] () {int g = g; return g+1;};
在我声明 local g
并从 global g
赋值的地方,输出是:
kitten: 1cat: 11
但我期待第一个示例 (21) 中的输出,因为我正在尝试创建本地 g
并从全局 g
分配它的值,它已经是修改值为 20.
代码是在 https://techiedelight.com/compiler/ 和 godbolt.org 上用 c++ (GCC 8.3.0) 编译的(最新的编译器,[=]
这是不允许的,但结果是一样的).
此时此刻,我对捕获and/or lambda的概念有点困惑。
auto kitten = [] () {int g = g; return g+1;};
您在这里根本没有使用全局变量。您正在使用本地 g
来初始化本地 g
。程序的行为未定义。
why int g = g;
trying to initialize local g by itself,
因为初始化器在声明局部 g
的点之后。
shouldn't that compiler initialize with the global g?
没有
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-capture,等号后的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;}
此代码有一个与 lambda 无关的错误。在局部变量定义 int g = g;
中,等号之前声明的变量在等号之后的初始化期间处于范围内。所以 g
被初始化为它自己的不确定值。向该不确定值加一是未定义的行为,因此结果不可预测。
我正在使用 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
的修改没有反映在我们的 [=21 中=].
小猫的结果是 21 因为据我所知,捕获所有内容,即按值捕获所有外部变量。
然后,当涉及到这个例子时,修改第一个lambda如下:
auto kitten = [] () {int g = g; return g+1;};
在我声明 local g
并从 global g
赋值的地方,输出是:
kitten: 1cat: 11
但我期待第一个示例 (21) 中的输出,因为我正在尝试创建本地 g
并从全局 g
分配它的值,它已经是修改值为 20.
代码是在 https://techiedelight.com/compiler/ 和 godbolt.org 上用 c++ (GCC 8.3.0) 编译的(最新的编译器,[=]
这是不允许的,但结果是一样的).
此时此刻,我对捕获and/or lambda的概念有点困惑。
auto kitten = [] () {int g = g; return g+1;};
您在这里根本没有使用全局变量。您正在使用本地 g
来初始化本地 g
。程序的行为未定义。
why
int g = g;
trying to initialize local g by itself,
因为初始化器在声明局部 g
的点之后。
shouldn't that compiler initialize with the global g?
没有
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-capture,等号后的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;}
此代码有一个与 lambda 无关的错误。在局部变量定义 int g = g;
中,等号之前声明的变量在等号之后的初始化期间处于范围内。所以 g
被初始化为它自己的不确定值。向该不确定值加一是未定义的行为,因此结果不可预测。