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.