下面的代码打印0,但我希望看到1.我的结论是,实际将捕获的参数传递给函数不会调用lambda函数,这更直观。我是对的还是我错过了什么?
#include <iostream>
int main(int argc, char **argv){
int value = 0;
auto incr_value = [&value]() { value++; };
auto print_value = [ value]() { std::cout << value << std::endl; };
incr_value();
print_value();
return 0;
}
答案 0 :(得分:29)
通过将捕获的参数实际传递给函数来调用Lambda函数 。
value
在定义lambda的位置等于0(并且捕获value
)。由于您是按价值捕获的,因此捕获后对value
所做的操作并不重要。
如果您通过引用捕获了value
,那么您会看到1打印,因为即使捕获点仍然相同(lambda定义),您将打印捕获对象的当前值,不是它被捕获时创建的副本。
答案 1 :(得分:14)
是的,捕获是在声明lambda的时候完成的,而不是在它被调用的时候完成的。将lambda视为一个函数对象,其构造函数将捕获的变量作为参数并将它们分配给相应的成员变量(值或引用,具体取决于捕获模式。)lambda的实际调用没有魔法,它只是一个定期operator()
调用底层函数对象。
在调用点捕获事物没有多大意义 - 如果lambda被返回或作为参数传递给另一个函数并在那里调用,会捕获什么?实际上有一些语言会以这种方式运行 - 如果在函数中引用变量x
,则假定它引用当前在调用点范围内的任何名为x
的变量。这称为动态范围。大多数语言使用的替代方法,因为它使程序的推理更简单,称为词法范围。
http://en.wikipedia.org/wiki/Lexical_scoping#Lexical_scoping_and_dynamic_scoping
答案 2 :(得分:5)
问题在于您的打印功能是按值而不是通过引用捕获的。
#include <iostream>
int main(int argc, char **argv){
int value = 0;
auto incr_value = [&value]() { value++; };
auto print_value = [ value]() { std::cout << value << std::endl; };
auto print_valueref = [ &value]() { std::cout << value << std::endl; };
incr_value();
print_value();
print_valueref();
return 0;
}
按预期输出0和1。第一个是按值捕获并在捕获点打印值;第二个捕获参考,然后打印其值。