在 C++ 中将参数传递给 lambda
Passing parameters to lambda in C++
我似乎错过了 C++ 中 lambda 机制的一些要点。这是代码:
std::vector<int> vec (5);
int init = 0;
std::generate(begin(vec), end(vec), [init]() mutable { return ++init; });
for (auto item : vec) {
std::cout << item << " ";
}
std::cout << std::endl << init << std::endl;
如果没有 mutable
它不会编译,因为我在 lambda 中更改 init
。
现在,据我所知,lambda 是为每个向量的项目调用的,其中 new fresh copy of init
为 0。
因此,每次都必须返回 1。
但是这段代码的输出是:
1 2 3 4 5
0
看起来 generate
在执行开始时通过副本 init
仅捕获一次 。但为什么?它应该像这样工作吗?
lambda 是编译器生成的结构,相当于:
struct lambda
{
int init = 0; // captured value
auto operator()() // non-const, due to `mutable`
{
return ++init;
}
};
因此,init
仅在 lambda 中被捕获和复制一次 - 多次调用 lambda 将不会再次捕获 init
。
您正在应对并看到 init 的初始值 -- 根据您的期望,您可能想要做的是通过引用捕获 init
.....
std::vector<int> vec (5);
int init = 0;
std::generate(begin(vec), end(vec), [&init]() mutable { return ++init; });
for (auto item : vec) {
std::cout << item << " ";
}
std::cout << std::endl << init << std::endl;
Now, as I understand lambda is called for each vector's item with a new fresh copy of init which is 0.
这是不正确的。 lambda 只是制作 class 并为其提供 operator()
的另一种方式。 lambda 的 []
部分描述了成员变量以及它们是通过引用还是值来捕获的。 lambda 的 ()
部分是 operator()
的参数列表,而 {}
部分是该函数的主体。 mutable
部分告诉编译器使 operator()
非 const
默认为 const
。
所以
[init]() mutable { return ++init; }
变成
struct compiler_generated_name
{
int init; // we captured by value
auto operator()() // since we used mutable this is non const
{
return ++init;
}
};
为了简化输入,我在这里使用了结构,但是 lambda 被指定为 class 类型,因此可以使用 class
。
这意味着 init
与上一次迭代的 init
相同,因为您只捕获了一次。记住这一点很重要,因为
auto generate_lambda()
{
int foo = 0;
return [&foo](){ return ++foo; };
}
当函数 returns 和使用它是未定义的行为时,会给您留下对 foo
的悬空引用。
你的错误在这里"Now, as I understand lambda is called for each vector's item with a new fresh copy of init which is 0"(我的斜体)。不;如您所见,lambda 是完全独立的,因此与矢量代码无关。 item
的初始化发生在每次评估 lambda 形式本身时(而不是每次调用结果值时);这里这意味着每次函数 generate
被调用:只有一次。
我似乎错过了 C++ 中 lambda 机制的一些要点。这是代码:
std::vector<int> vec (5);
int init = 0;
std::generate(begin(vec), end(vec), [init]() mutable { return ++init; });
for (auto item : vec) {
std::cout << item << " ";
}
std::cout << std::endl << init << std::endl;
如果没有 mutable
它不会编译,因为我在 lambda 中更改 init
。
现在,据我所知,lambda 是为每个向量的项目调用的,其中 new fresh copy of init
为 0。
因此,每次都必须返回 1。
但是这段代码的输出是:
1 2 3 4 5
0
看起来 generate
在执行开始时通过副本 init
仅捕获一次 。但为什么?它应该像这样工作吗?
lambda 是编译器生成的结构,相当于:
struct lambda
{
int init = 0; // captured value
auto operator()() // non-const, due to `mutable`
{
return ++init;
}
};
因此,init
仅在 lambda 中被捕获和复制一次 - 多次调用 lambda 将不会再次捕获 init
。
您正在应对并看到 init 的初始值 -- 根据您的期望,您可能想要做的是通过引用捕获 init
.....
std::vector<int> vec (5);
int init = 0;
std::generate(begin(vec), end(vec), [&init]() mutable { return ++init; });
for (auto item : vec) {
std::cout << item << " ";
}
std::cout << std::endl << init << std::endl;
Now, as I understand lambda is called for each vector's item with a new fresh copy of init which is 0.
这是不正确的。 lambda 只是制作 class 并为其提供 operator()
的另一种方式。 lambda 的 []
部分描述了成员变量以及它们是通过引用还是值来捕获的。 lambda 的 ()
部分是 operator()
的参数列表,而 {}
部分是该函数的主体。 mutable
部分告诉编译器使 operator()
非 const
默认为 const
。
所以
[init]() mutable { return ++init; }
变成
struct compiler_generated_name
{
int init; // we captured by value
auto operator()() // since we used mutable this is non const
{
return ++init;
}
};
为了简化输入,我在这里使用了结构,但是 lambda 被指定为 class 类型,因此可以使用 class
。
这意味着 init
与上一次迭代的 init
相同,因为您只捕获了一次。记住这一点很重要,因为
auto generate_lambda()
{
int foo = 0;
return [&foo](){ return ++foo; };
}
当函数 returns 和使用它是未定义的行为时,会给您留下对 foo
的悬空引用。
你的错误在这里"Now, as I understand lambda is called for each vector's item with a new fresh copy of init which is 0"(我的斜体)。不;如您所见,lambda 是完全独立的,因此与矢量代码无关。 item
的初始化发生在每次评估 lambda 形式本身时(而不是每次调用结果值时);这里这意味着每次函数 generate
被调用:只有一次。