试图理解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
的值,即使我们已经尝试捕获它?
获得理想结果的方法是什么?
答案 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即使其数据是实现也是实现定义的。等