The C++ mutable lambda expressions as stateful function objects

Question | Jul 13, 2016 | nextptr 

Intro

The variables captured by value (or copy) cannot be modified in a lambda expression by default. Let's take an example of a lambda that captures two variables, one by value and the other by reference from its outer scope:

void spam() {
 int v = 0, r = 0;
 auto l = [v, &r]() { //Capture v by value and r by ref
   v++; //ERROR
   r++; //OK
 };
 l();
}

As shown above, it is an error to modify a variable that is captured by value, but a variable captured by reference can be modified in the lambda. A lambda expression is essentially a function object with an overloaded function-call operator (operator ()). That overloaded function-call operator is const by default. Here is the above code with an equivalent custom function object:

struct Lambda {
 Lambda(int v_, int& r_)
  :v(v_),r(r_){}

 //overloded const function-call operator
 void operator()() const { // 'const'
   v++; //ERROR
   r++; //OK
 }
 int v;
 int& r;
};

void spam() {
  int v = 0, r = 0;
  Lambda l(v, r);
  l();
}

However, this default behavior can be overridden by the mutable qualifier. A mutable lambda expression is allowed to change the variables that are captured by value. A mutable lambda expression is equivalent to a function object with a non-const overloaded function-call operator. As an example, foo is a mutable lambda expression that can modify the value-captured variable x:

int x = 0;
auto foo = [x] () mutable { 
 /* "x" cannot be modified without 
      keyword mutable. */
 x++; //OK
 return x;
};

Mutable Lambda as Stateful Function Object

It might not be obvious that mutable lambda expressions are like stateful function objects. The captured variable x is the state of foo, which is changed every time foo is called. Consider the following code to see what is so interesting about it:

 // call foo
std::cout << foo() << " ";

// assign foo to bar
auto bar = foo;

// call foo again
std::cout << foo() << " ";

// call bar
std::cout << bar() << " ";

In brief, we call foo and then assign it to another variable bar, and then we call foo (again) followed by a call to bar. What would be the output of the above? Select the correct answer below (check the Explanations for details):