lambda-capture: capture-default capture-list capture-default , capture-list
capture-default: & =
capture-list: capture ...opt capture-list , capture ...opt
capture: simple-capture init-capture
simple-capture: identifier & identifier this * this
init-capture: identifier initializer & identifier initializer
The body of a lambda-expression may refer to variables with automatic storage duration and the *this object (if any) of enclosing block scopes by capturing those entities, as described below.
If a lambda-capture includes a capture-default that is &, no identifier in a simple-capture of that lambda-capture shall be preceded by &. If a lambda-capture includes a capture-default that is =, each simple-capture of that lambda-capture shall be of the form “& identifier” or “* this”. [ Note: The form [&,this] is redundant but accepted for compatibility with ISO C++ 2014. — end note ] Ignoring appearances in initializers of init-captures, an identifier or this shall not appear more than once in a lambda-capture. [ Example:
struct S2 { void f(int i); };
void S2::f(int i) {
[&, i]{ }; // OK
[&, &i]{ }; // error: i preceded by & when & is the default
[=, *this]{ }; // OK
[=, this]{ }; // error: this when = is the default
[i, i]{ }; // error: i repeated
[this, *this]{ }; // error: this appears twice
}— end example ]
A lambda-expression whose smallest enclosing scope is a block scope is a local lambda expression; any other lambda-expression shall not have a capture-default or simple-capture in its lambda-introducer. The reaching scope of a local lambda expression is the set of enclosing scopes up to and including the innermost enclosing function and its parameters. [ Note: This reaching scope includes any intervening lambda-expressions. — end note ]
The identifier in a simple-capture is looked up using the usual rules for unqualified name lookup; each such lookup shall find an entity. An entity that is designated by a simple-capture is said to be explicitly captured, and shall be *this (when the simple-capture is “this” or “* this”) or a variable with automatic storage duration declared in the reaching scope of the local lambda expression.
If an identifier in a simple-capture appears as the declarator-id of a parameter of the lambda-declarator's parameter-declaration-clause, the program is ill-formed. [ Example:
void f() {
int x = 0;
auto g = [x](int x) { return 0; } // error: parameter and simple-capture have the same name
}— end example ]
An init-capture behaves as if it declares and explicitly captures a variable of the form “auto init-capture ;” whose declarative region is the lambda-expression's compound-statement, except that:
if the capture is by copy (see below), the non-static data member declared for the capture and the variable are treated as two different ways of referring to the same object, which has the lifetime of the non-static data member, and no additional copy and destruction is performed, and
if the capture is by reference, the variable's lifetime ends when the closure object's lifetime ends.
[ Note: This enables an init-capture like “x = std::move(x)”; the second “x” must bind to a declaration in the surrounding context. — end note ] [ Example:
int x = 4;
auto y = [&r = x, x = x+1]()->int {
r += 2;
return x+2;
}(); // Updates ::x to 6, and initializes y to 7.
auto z = [a = 42](int a) { return 1; } // error: parameter and local variable have the same name
— end example ]
A lambda-expression with an associated capture-default that does not explicitly capture *this or a variable with automatic storage duration (this excludes any id-expression that has been found to refer to an init-capture's associated non-static data member), is said to implicitly capture the entity (i.e., *this or a variable) if the compound-statement:
odr-uses the entity (in the case of a variable),
odr-uses this (in the case of the object designated by *this), or
names the entity in a potentially evaluated expression where the enclosing full-expression depends on a generic lambda parameter declared within the reaching scope of the lambda-expression.
[ Example:
void f(int, const int (&)[2] = {}) { } // #1
void f(const int&, const int (&)[1]) { } // #2
void test() {
const int x = 17;
auto g = [](auto a) {
f(x); // OK: calls #1, does not capture x
};
auto g2 = [=](auto a) {
int selector[sizeof(a) == 1 ? 1 : 2]{};
f(x, selector); // OK: is a dependent expression, so captures x
};
}— end example ] All such implicitly captured entities shall be declared within the reaching scope of the lambda expression. [ Note: The implicit capture of an entity by a nested lambda-expression can cause its implicit capture by the containing lambda-expression (see below). Implicit odr-uses of this can result in implicit capture. — end note ]
An entity is captured if it is captured explicitly or implicitly. An entity captured by a lambda-expression is odr-used in the scope containing the lambda-expression. If *this is captured by a local lambda expression, its nearest enclosing function shall be a non-static member function. If a lambda-expression or an instantiation of the function call operator template of a generic lambda odr-uses this or a variable with automatic storage duration from its reaching scope, that entity shall be captured by the lambda-expression. If a lambda-expression captures an entity and that entity is not defined or captured in the immediately enclosing lambda expression or function, the program is ill-formed. [ Example:
void f1(int i) {
int const N = 20;
auto m1 = [=]{
int const M = 30;
auto m2 = [i]{
int x[N][M]; // OK: N and M are not odr-used
x[0][0] = i; // OK: i is explicitly captured by m2 and implicitly captured by m1
};
};
struct s1 {
int f;
void work(int n) {
int m = n*n;
int j = 40;
auto m3 = [this,m] {
auto m4 = [&,j] { // error: j not captured by m3
int x = n; // error: n implicitly captured by m4 but not captured by m3
x += m; // OK: m implicitly captured by m4 and explicitly captured by m3
x += i; // error: i is outside of the reaching scope
x += f; // OK: this captured implicitly by m4 and explicitly by m3
};
};
}
};
}
struct s2 {
double ohseven = .007;
auto f() {
return [this] {
return [*this] {
return ohseven; // OK
}
}();
}
auto g() {
return [] {
return [*this] { }; // error: *this not captured by outer lambda-expression
}();
}
};— end example ]
A lambda-expression appearing in a default argument shall not implicitly or explicitly capture any entity. [ Example:
void f2() {
int i = 1;
void g1(int = ([i]{ return i; })()); // ill-formed
void g2(int = ([i]{ return 0; })()); // ill-formed
void g3(int = ([=]{ return i; })()); // ill-formed
void g4(int = ([=]{ return 0; })()); // OK
void g5(int = ([]{ return sizeof i; })()); // OK
}— end example ]
An entity is captured by copy if
it is implicitly captured, the capture-default is =, and the captured entity is not *this, or
it is explicitly captured with a capture that is not of the form this, & identifier, or & identifier initializer.
For each entity captured by copy, an unnamed non-static data member is declared in the closure type. The declaration order of these members is unspecified. The type of such a data member is the referenced type if the entity is a reference to an object, an lvalue reference to the referenced function type if the entity is a reference to a function, or the type of the corresponding captured entity otherwise. A member of an anonymous union shall not be captured by copy.
Every id-expression within the compound-statement of a lambda-expression that is an odr-use of an entity captured by copy is transformed into an access to the corresponding unnamed data member of the closure type. [ Note: An id-expression that is not an odr-use refers to the original entity, never to a member of the closure type. Furthermore, such an id-expression does not cause the implicit capture of the entity. — end note ] If *this is captured by copy, each odr-use of this is transformed into a pointer to the corresponding unnamed data member of the closure type, cast to the type of this. [ Note: The cast ensures that the transformed expression is a prvalue. — end note ] An id-expression within the compound-statement of a lambda-expression that is an odr-use of a reference captured by reference refers to the entity to which the captured reference is bound and not to the captured reference. [ Note: The validity of such captures is determined by the lifetime of the object to which the reference refers, not by the lifetime of the reference itself. — end note ] [ Example:
void f(const int*);
void g() {
const int N = 10;
[=] {
int arr[N]; // OK: not an odr-use, refers to automatic variable
f(&N); // OK: causes N to be captured; &N points to
// the corresponding member of the closure type
};
}
auto h(int &r) {
return [&] {
++r; // Valid after h returns if the lifetime of the
// object to which r is bound has not ended
};
}— end example ]
An entity is captured by reference if it is implicitly or explicitly captured but not captured by copy. It is unspecified whether additional unnamed non-static data members are declared in the closure type for entities captured by reference. If declared, such non-static data members shall be of literal type. [ Example:
// The inner closure type must be a literal type regardless of how reference captures are represented.
static_assert([](int n) { return [&n] { return ++n; }(); }(3) == 4);— end example ] A bit-field or a member of an anonymous union shall not be captured by reference.
If a lambda-expression m2 captures an entity and that entity is captured by an immediately enclosing lambda-expression m1, then m2's capture is transformed as follows:
if m1 captures the entity by copy, m2 captures the corresponding non-static data member of m1's closure type;
if m1 captures the entity by reference, m2 captures the same entity captured by m1.
[ Example: The nested lambda expressions and invocations below will output 123234.
int a = 1, b = 1, c = 1;
auto m1 = [a, &b, &c]() mutable {
auto m2 = [a, b, &c]() mutable {
std::cout << a << b << c;
a = 4; b = 4; c = 4;
};
a = 3; b = 3; c = 3;
m2();
};
a = 2; b = 2; c = 2;
m1();
std::cout << a << b << c;— end example ]
Every occurrence of decltype((x)) where x is a possibly parenthesized id-expression that names an entity of automatic storage duration is treated as if x were transformed into an access to a corresponding data member of the closure type that would have been declared if x were an odr-use of the denoted entity. [ Example:
void f3() {
float x, &r = x;
[=] { // x and r are not captured (appearance in a decltype operand is not an odr-use)
decltype(x) y1; // y1 has type float
decltype((x)) y2 = y1; // y2 has type float const& because this lambda is not mutable and x is an lvalue
decltype(r) r1 = y1; // r1 has type float& (transformation not considered)
decltype((r)) r2 = y2; // r2 has type float const&
};
}— end example ]
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, and the non-static data members corresponding to the init-captures are initialized as indicated by the corresponding initializer (which may be copy- or direct-initialization). (For array members, the array elements are direct-initialized in increasing subscript order.) These initializations are performed in the (unspecified) order in which the non-static data members are declared. [ Note: This ensures that the destructions will occur in the reverse order of the constructions. — end note ]
[ Note: If a non-reference entity is implicitly or explicitly captured by reference, invoking the function call operator of the corresponding lambda-expression after the lifetime of the entity has ended is likely to result in undefined behavior. — end note ]
A simple-capture followed by an ellipsis is a pack expansion. An init-capture followed by an ellipsis is ill-formed. [ Example:
template<class... Args>
void f(Args... args) {
auto lm = [&, args...] { return g(args...); };
lm();
}— end example ]