I saw the equivalent of this code earlier, and I was a little surprised to learn that it worked as intended:
#include <iostream>
int main()
{
int a = 10;
[=]() mutable {
[&]() {
a += 10;
std::cout << "nested lambda: a=" << a << std::endl;
}(); // call nested lambda
}(); // call first lambda
std::cout << "a=" << a << std::endl;
}
As was desired, the output is
nested lambda: a=20
a=10
I was surprised that the compiler figures out that a
is used in the nested lambda, and correctly captures it by value in the first lambda even though it is not explicitly used there. I.e., the compiler must make the connection between the a
in the nested lambda, and a
in the outer scope. I thought that the argument capture would need to be explicit (i.e. [a]
in the first lambda, [&a]
in the nested), for it to work.
What are the deduction rules for automatic argument capture?
This is described in [expr.prim.lambda.capture]p7:
For the purposes of lambda capture, an expression potentially references local entities as follows:
An id-expression that names a local entity potentially references that entity; an id-expression that names one or more non-static class members and does not form a pointer to member ([expr.unary.op]) potentially references
*this
.A
this
expression potentially references*this
.A lambda-expression potentially references the local entities named by its simple-captures.
If an expression potentially references a local entity within a declarative region in which it is odr-usable, and the expression would be potentially evaluated if the effect of any enclosing
typeid
expressions ([expr.typeid]) were ignored, the entity is said to be implicitly captured by each intervening lambda-expression with an associated capture-default that does not explicitly capture it.
In other words:
A lambda implicitly captures under the following circumstances if the usage requires a definition, typeid
expressions are ignored, and they are not explicitly captured:
a variable is named; or if the name of a non-static class member (not counting pointer to members) appears, then *this
is implicitly captured, or
this
appears, then *this
is implicitly captured
The implicitly captured entities are implicitly captured by each intervening lambda with a default capture.
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