C ++ 11 lambda按值捕获在声明点捕获

时间:2012-07-22 10:22:47

标签: c++ lambda c++11

下面的代码打印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;
}

3 个答案:

答案 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。第一个是按值捕获并在捕获点打印值;第二个捕获参考,然后打印其值。