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