How are lambda captures initialized in case of nested lambdas?
First, note that whether a capture is by copy or by reference depends only on the lambda expression's own lambda-introducer (the initial []
part), per C++11 [expr.prim.lambda] paragraph 14 (or C++17 [expr.prim.lambda.capture] paragraph 10).
The pieces you quoted from C++11 [expr.prim.lambda]/16 (or the same in C++17 [expr.prim.lambda.capture]/13) change only what entity is captured, not the type of the capture. So in the example, the inner lambda used to initialize m2
captures the b
from the original definition, by copy.
Then, note C++11 [expr.prim.lambda]/21:
When the lambda-expression is evaluated, the entities that are captured by copy are used to direct-initialize each corresponding non-static data member of the resulting closure object.
(C++17 [expr.prim.lambda.capture]/15 starts out the same, but additional wording is added for the init-capture syntax like [var=init]
.)
In the example, the inner lambda-expression for initializing m2
is evaluated, and the closure object's member for b
is initialized, each time m1.operator()
is invoked, not in the order the lambda-expression appears in the code. Since the lambda for m2
captures the original b
by copy, it gets the value of that b
at the time m1
is called. If m1
were called multiple times, that initial value for b
could be different each time.
— if
m1
captures the entity by reference,m2
captures the same entity captured bym1
.
Yes, so b
in m2
's capture list captures not the reference itself (the capture of m1
, that is), but the object that it points to.
But whether m2
captures b
by value or by reference is determined solely by what's written in m2
's capture list. There's no &
before b
, so b
is captured by value.
when is
b
insidem2
initialised?
When control reaches auto m2 = ...;
. At that point, the reference to b
stored in m1
is examined, and the object it points to is copied into m2
.
Here's an easier explanation.
When you capture a reference by value, you make a copy of the object that it points to.
When you capture a reference by reference, you make a reference to the object that it points to.
Here, "capturing a reference" applies equally well to capturing actual references, and to capturing reference-captures of enclosing lambdas.