【问题标题】:Trying to understand lambdas试图理解 lambdas
【发布时间】:2016-08-29 10:58:25
【问题描述】:

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

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 的值,即使我们已经尝试捕获它?

而获得预期结果的方法是什么?

【问题讨论】:

  • 请用标题描述问题。是的,您正在尝试理解 lambda,但这并不能告诉我们您实际要问的内容。 (我正在考虑自己编辑它,但我不喜欢我提出的想法。)

标签: c++ lambda


【解决方案1】:

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

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

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

【讨论】:

  • 另外,如果你真的想要这种行为,timesFive 这个名字有点误导
  • @SteveCox 我很确定这只是一个展示概念的学术示例。我们也可以称它为 foo、foobar、...。当然你是对的,如果这是一个真实世界的例子。
【解决方案2】:

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 的行为。

如果你在名字前面加上&amp;,一个非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 是实现定义的,即使它的数据是。等等。

【讨论】:

  • 很好的洞察力。很久以前,我们让 Cfront(由 Bjarne Stroustrup 提供)来了解 C++ 的“内部工作原理”。这些天有类似的事情吗?你是如何推测你的伪代码的?直觉?
  • @black 该标准描述了 lambda 是什么。它不像for(:) 循环那样“好像”,但它非常明确。
猜你喜欢
  • 1970-01-01
  • 2020-04-06
  • 2023-03-07
  • 2011-03-28
  • 2011-11-27
  • 2017-08-11
  • 1970-01-01
相关资源
最近更新 更多