试图了解lambdas

时间:2016-08-29 10:58:26

标签: c++ lambda

试图理解C ++中的lambdas,我不明白的是:

int multiplier = 5;
auto timesFive = [multiplier](int a) { return a * multiplier; }; 
std::cout << timesFive(2) << '\n'; // Prints 10

multiplier = 15;
std::cout << timesFive(2) << '\n'; // Still prints 2*5 == 10 (???) - Should it be 30?

当程序第二次调用timesFive()时,我希望结果为30.但为什么结果是Still prints 2*5 == 10,而不是prints 2*15 == 30?也许lambda函数以某种方式无法跟踪multiplier的值,即使我们已经尝试捕获它?

获得理想结果的方法是什么?

2 个答案:

答案 0 :(得分:90)

您按值捕获了multiplier,这意味着它已被复制到lambda中。您需要通过引用来捕获它:

int multiplier = 5;
auto timesFive = [&multiplier](int a) { return a * multiplier; }; 
std::cout << timesFive(2);

multiplier = 15;
std::cout << timesFive(2); 

答案 1 :(得分:43)

Lambda是一种不可分类的合成糖及其实例。有时候将代码扩展到这个不起眼的类可以帮助理解正在发生的事情。

[ capture_list ]( arg_list ) -> return_value_clause_opt { body };

非常粗略(伪代码):

struct anonymous_type {
  capture_list;
  auto operator()( arg_list ) const -> return_value_clause_opt {
    body
  }
  anonymous_type( capture_list_in ):capture_list(capture_list_in) {}
};

如果您使用其简单名称在capture_list中列出变量,则复制到匿名类中的副本中。

所以你的timesFive成了

struct __secret_name__ {
  int multiplier;
  int operator()(int a) const { return a*multiplier; }
};
int multiplier = 5;
auto timesFive = __secret_name__{multiplier};

很明显,更改上述代码中的multiplier不会改变timesFive的行为。

如果您在名称前放置&,则非匿名类中会放置非const 引用

struct __secret_name__ {
  int& multiplier;
  int operator()(int a) const { return a*multiplier; }
};
int multiplier = 5;
auto timesFive = __secret_name__{multiplier};

现在,更改multiplier会改变timesFive的行为,因为timesFive会将引用保存到乘数,而不是它的副本。

为简洁起见,上面省略了一些细节。名称__secret_name__仅用于展示。 lamba的成员变量实际上不是公共的。简单可构造的lambda即使其数据是实现也是实现定义的。等