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]{ }; [&, &i]{ }; [=, *this]{ }; [=, this]{ }; [i, i]{ }; [this, *this]{ }; }
— 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; }(); auto z = [a = 42](int a) { return 1; }
— 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] = {}) { } void f(const int&, const int (&)[1]) { } void test() { const int x = 17; auto g = [](auto a) { f(x); }; auto g2 = [=](auto a) { int selector[sizeof(a) == 1 ? 1 : 2]{}; f(x, selector); }; }
— 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]; x[0][0] = i; }; }; struct s1 { int f; void work(int n) { int m = n*n; int j = 40; auto m3 = [this,m] { auto m4 = [&,j] { int x = n; x += m; x += i; x += f; }; }; } }; } struct s2 { double ohseven = .007; auto f() { return [this] { return [*this] { return ohseven; } }(); } auto g() { return [] { return [*this] { }; }(); } };
— 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; })()); void g2(int = ([i]{ return 0; })()); void g3(int = ([=]{ return i; })()); void g4(int = ([=]{ return 0; })()); void g5(int = ([]{ return sizeof i; })()); }
— 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]; f(&N); }; } auto h(int &r) { return [&] { ++r; }; }
— 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:
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; [=] { decltype(x) y1; decltype((x)) y2 = y1; decltype(r) r1 = y1; decltype((r)) r2 = y2; }; }
— 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 ]
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4