Trying to understand lambdas
Trying to understand lambdas in C++, what I do not understand is this:
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?
When the program calls the timesFive()
the second time, I expect the result to be 30. But why is the result Still prints 2*5 == 10
, not prints 2*15 == 30
? Perhaps the lambda function somehow cannot track the value of multiplier
, even though we have already tried to capture it?
And what is the way to get the desired result?
Solution 1:
You captured multiplier
by value, which means it was copied into the lambda. You need to capture it by reference:
int multiplier = 5;
auto timesFive = [&multiplier](int a) { return a * multiplier; };
std::cout << timesFive(2);
multiplier = 15;
std::cout << timesFive(2);
Solution 2:
Lambdas are syntatic sugar for an unnamable class and the instance thereof. Sometimes expanding your code out to what this unnamable class can help understanding what is going on.
[ capture_list ]( arg_list ) -> return_value_clause_opt { body };
becomes very roughly (pseudo-code):
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) {}
};
If you list a variable in capture_list
by its plain name, it is copied into a copy within the anonymous class.
So your timesFive
became
struct __secret_name__ {
int multiplier;
int operator()(int a) const { return a*multiplier; }
};
int multiplier = 5;
auto timesFive = __secret_name__{multiplier};
It should be pretty clear that changing multiplier
in the above code won't change the behavior of timesFive
.
If you put a &
in front of the name, a non-const
reference is placed within the anonymous class.
struct __secret_name__ {
int& multiplier;
int operator()(int a) const { return a*multiplier; }
};
int multiplier = 5;
auto timesFive = __secret_name__{multiplier};
now, changing multiplier
will change the behavior of timesFive
, because timesFive
holds a reference to multiplier, not a copy of it.
Some details skipped above for brevity. The name __secret_name__
is only for exposition. The member variables of the lamba are not actually public. The lambda being trivially constructible is implementation defined even if its data is. Etc.