Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trying to understand lambdas

Tags:

c++

lambda

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); 

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.