C++11 lambda捕获通过声明点的值捕获

C++11 lambda capture by value captures at declaration point

本文关键字:声明 lambda C++11      更新时间:2023-10-16

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

Lambda函数是通过实际将捕获的参数传递给函数来调用的。

在定义lambda的点处value等于0(并且捕获value)。由于您是按值进行捕获的,因此捕获后对value做什么并不重要。

如果您通过引用捕获了value,那么您将看到打印的1,因为即使捕获点仍然相同(lambda定义),您也将打印捕获对象的当前值,而不是捕获时创建的对象的副本。

是的,捕获是在声明lambda时完成的,而不是在调用lambda时。把lambda想象成一个函数对象,它的构造函数将捕获的变量作为参数,并将它们分配给相应的成员变量(根据捕获模式,可以是值或引用)。lambda的实际调用没有魔力,它只是底层函数对象的常规operator()调用。

在调用点捕获东西没有多大意义——如果lambda被返回或作为参数传递给另一个函数并在那里调用,会捕获什么?实际上,有些语言确实有这种行为——如果您在函数中引用变量x,则假定它引用了调用时当前范围内的任何名为x的变量。这称为动态作用域。大多数语言都使用另一种方法,因为它使程序的推理更加简单,称为词法范围。

http://en.wikipedia.org/wiki/Lexical_scoping#Lexical_scoping_and_dynamic_scoping

问题是您的打印函数是按值捕获的,而不是按引用捕获的。

#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。第一个是按值捕获的,并在捕获点打印值;第二个捕获引用,然后打印其值。