In C++ you can declare lambdas for example like this:
int x = 5; auto a = [=]() mutable { ++x; std::cout << x << '\n'; }; auto b = [&]() { ++x; std::cout << x << '\n'; };
Both let me modify x
, so what is the difference?
The mutable keyword is used so that the body of the lambda expression can modify its copies of the external variables x and y , which the lambda expression captures by value. Because the lambda expression captures the original variables x and y by value, their values remain 1 after the lambda executes.
Captures default to const value. By default, variables are captured by const value . This means when the lambda is created, the lambda captures a constant copy of the outer scope variable, which means that the lambda is not allowed to modify them.
The capture list defines the outside variables that are accessible from within the lambda function body. The only capture defaults are. & (implicitly capture the used automatic variables by reference) and. = (implicitly capture the used automatic variables by copy).
5. Which of the following operator is used to capture all the external variable by reference? Explanation: The lambda expression uses & operator to capture the external variable by reference.
The first will only modify its own copy of x
and leave the outside x
unchanged. The second will modify the outside x
.
Add a print statement after trying each:
a(); std::cout << x << "----\n"; b(); std::cout << x << '\n';
This is expected to print:
6 5 ---- 6 6
It may help to consider that lambda
[...] expressions provide a concise way to create simple function objects
(see [expr.prim.lambda] of the Standard)
They have
[...] a public inline function call operator [...]
which is declared as a const
member function, but only
[...] if and only if the lambda expression’s parameter-declaration-clause is not followed by
mutable
You can think of as if
int x = 5; auto a = [=]() mutable { ++x; std::cout << x << '\n'; }; ==> int x = 5; class __lambda_a { int x; public: __lambda_a () : x($lookup-one-outer$::x) {} inline void operator() { ++x; std::cout << x << '\n'; } } a;
and
auto b = [&]() { ++x; std::cout << x << '\n'; }; ==> int x = 5; class __lambda_b { int &x; public: __lambda_b() : x($lookup-one-outer$::x) {} inline void operator() const { ++x; std::cout << x << '\n'; } // ^^^^^ } b;
Q: But if it is a const
function, why can I still change x
?
A: You are only changing the outside x
. The lambda's own x
is a reference, and the operation ++x
does not modify the reference, but the refered value.
This works because in C++, the constness of a pointer/reference does not change the constness of the pointee/referencee seen through it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With