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
Тело a lambda-expressionможет ссылаться на переменные с автоматической продолжительностью хранения и*this объект (если есть) охватывающих областей блока путем захвата этих сущностей, как описано ниже.
Если a lambda-captureвключает в себя, capture-defaultто&ни одному идентификатору в a simple-captureиз этого lambda-captureне должно предшествовать&. Если a lambda-captureвключает в себя, capture-defaultто=каждый simple-captureиз них lambda-captureдолжен иметь форму « » или « ». [ Форма является избыточным , но для совместимости с ISO C ++ 2014 ] Игнорирование появления в из , идентификатора или не должен появляться более одного раза в . [& identifier* this Note: [&,this] — end note initializers init-capturesthis 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чья наименьшая охватывающая область видимости - этоblock scope alocal lambda expression; любой другой lambda-expressionне должен иметь capture-defaultили simple-captureв своем lambda-introducer.reaching scope Локального лямбда - выражения является множество вмещающих прицелы вплоть до самой внутренней функции и ее параметры ограждающих. [ Note: Этот охват включает любое вмешательство lambda-expressions. ] — end note
Поиск identifierв a simple-captureвыполняется по обычным правилам дляunqualified name lookup; каждый такой поиск должен найти объект. Сущность, обозначенная a simple-capture , называетсяexplicitly capturedи должна быть*this (когда simple-capture это «this» или «* this») или переменной с автоматической продолжительностью хранения, объявленной в области охвата локального лямбда-выражения.
Если a identifierв a simple-captureпоявляется как declarator-idпараметр lambda-declarators parameter-declaration-clause, программа имеет неправильный формат. [ 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ведет себя так, как будто он объявляет и явно захватывает переменную формы « », декларативной областью которой является 's , за исключением того, что: auto init-capture;lambda-expressioncompound-statement
если захват осуществляется копированием (см. ниже), нестатический член данных, объявленный для захвата, и переменная обрабатываются как два разных способа ссылки на один и тот же объект, у которого есть время жизни нестатического члена данных, и дополнительное копирование и уничтожение не производится, и
если захват осуществляется по ссылке, время жизни переменной заканчивается, когда заканчивается время жизни закрывающего объекта.
[ Note: Это позволяет использовать init-captureподобное «x = std::move(x)»; второй «x» должен быть привязан к объявлению в окружающем контексте. ] [ — 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со связанным capture-default, который явно не захватывает,*this или переменная с автоматической продолжительностью хранения (это исключает все, id-expression что было обнаружено как относящееся к init-captureсвязанному нестатическому элементу данных), называетсяimplicitly capture сущностью (т. Е. *this Или переменной) если compound-statement:
odr-uses сущность (в случае переменной),
odr-usesthis (в случае объекта, обозначенного*this), или
именует сущность вpotentially evaluated выражении, в котором включающее полное выражение зависит от общего лямбда-параметра, объявленного в пределах достигаемой области 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 ] Все такие неявно захваченные объекты должны быть объявлены в пределах области действия лямбда-выражения. [ Note: Неявный захват объекта вложенным lambda-expressionможет вызвать его неявный захват содержащим lambda-expression(см. Ниже). Неявное использование odrthis может привести к неявному захвату. ] — end note
Сущность -captured это если она захвачена явно или неявно. Сущность, захваченная объектом, lambda-expressionнаходитсяodr-used в области, содержащей lambda-expression. Если*this он захвачен локальным лямбда-выражением, его ближайшая включающая функция должна быть нестатической функцией-членом. Если a lambda-expressionили создание экземпляра шаблона оператора вызова функции универсальной лямбда-выраженияodr-usesthis или переменной с автоматической продолжительностью хранения из достигаемой области действия, этот объект должен быть захвачен lambda-expression. Если a lambda-expressionзахватывает сущность, и эта сущность не определена или не зафиксирована в непосредственно включающем лямбда-выражении или функции, программа сформирована неправильно. [ 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 ]
lambda-expressionПоявляется в аргументе по умолчанию не будет неявно или явно захватить любой объект. [ 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 ]
Сущность - этоcaptured by copy если
он неявно захватывается, capture-defaultесть=, а захваченный объект нет*this, или
он явно захваченный с захватом , который не в форме this, или . & identifier& identifier initializer
Для каждой сущности, захваченной копией, в типе замыкания объявляется безымянный нестатический член данных. Порядок объявления этих членов не указан. Тип такого члена данных - это ссылочный тип, если сущность является ссылкой на объект, ссылка lvalue на ссылочный тип функции, если сущность является ссылкой на функцию, или тип соответствующей захваченной сущности в противном случае. Член анонимного союза не может быть записан копией.
Каждый элемент id-expressionвнутри compound-statementa, lambda-expressionкоторый являетсяodr-use сущностью, захваченной копией, преобразуется в доступ к соответствующему безымянному элементу данных типа закрытия. [ , Что не является ODR использование относится к оригинальной сущности, никогда не члену типа закрытия. Более того, такое не вызывает неявного захвата объекта. ] Если захватывается копией, каждое использование odr преобразуется в указатель на соответствующий безымянный элемент данных типа замыкания, на тип . [ Приведение гарантирует, что преобразованное выражение является prvalue. ] Элемент внутри элемента a, который является случайным использованием ссылки, захваченной посредством ссылки, относится к объекту, к которому привязана захваченная ссылка, а не к захваченной ссылке. [ Действительность таких захватов определяется временем жизни объекта, на который ссылается ссылка, а не временем жизни самой ссылки. ] [ Note: id-expressionid-expression — end note *this this cast this Note: — end note id-expressioncompound-statementlambda-expression Note: — 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 ]
Сущность -captured by reference это если она неявно или явно захвачена, но не копируется. Не указано, объявляются ли дополнительные безымянные нестатические элементы данных в типе замыкания для сущностей, захваченных по ссылке. Если объявлено, такие нестатические элементы данных должны иметь буквальный тип. [ 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 lambda-expressionm2 захватывает сущность, и эта сущность захватывается немедленным включением lambda-expression m1, то m2захват преобразуется следующим образом:
еслиm1 захватывает сущность копией, m2 захватывает соответствующий нестатический член данных типаm1закрытия;
еслиm1 захватывает объект по ссылке, m2 захватывает тот же объект, захваченныйm1.
[ Example: Вложенные лямбда-выражения и вызовы, приведенные ниже, будут выведены 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 ]
Каждое вхождение в скобки ,decltype((x)) гдеx возможно заключенное в скобки id-expressionимя объекта с автоматической продолжительностью хранения, обрабатывается так, как если бы оноx было преобразовано в доступ к соответствующему члену данных типа закрытия, который был бы объявлен, если быx было использование обозначенной сущности odr. [ 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 ]
Когда lambda-expressionоценивается, объекты, захваченные копией, используются для прямой инициализации каждого соответствующего нестатического элемента данных результирующего объекта закрытия, а нестатические элементы данных, соответствующие объекту, init-captures инициализируются, как указано соответствующими initializer(которые может быть копией или прямой инициализацией). (Для членов массива элементы массива инициализируются напрямую в порядке возрастания индекса.) Эти инициализации выполняются в (неуказанном) порядке, в котором объявлены нестатические элементы данных. [ Note: Это гарантирует, что разрушения будут происходить в порядке, обратном построению. ] — end note
[ Note: Если не ссылочный объект неявно или неявно захватывается ссылкой, вызов оператора вызова функции соответствующего lambda-expression после того, как время жизни объекта закончилось, вероятно, приведет к неопределенному поведению. ] — end note
А, simple-captureза которым следует многоточие, - этоpack expansion. Знак, init-captureза которым следует многоточие, имеет неправильный формат. [ Example:
template<class... Args> void f(Args... args) { auto lm = [&, args...] { return g(args...); }; lm(); }
— end example ]