32

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

3 回答 3

29

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

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

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

于 2012-07-22T10:41:40.943 回答
14

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

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

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

于 2012-07-22T12:32:46.197 回答
5

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

#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;
}

Outputs 0 and 1 as expected. The first one is captured by value and prints the value at the point of capture; the second one captures the reference and then prints its value.

于 2012-07-22T21:44:53.010 回答