8 Expressions [expr]

8.1 Primary expressions [expr.prim]

primary-expression:
	literal
	this
	( expression )
	id-expression
	lambda-expression
	fold-expression

8.1.1 Literals [expr.prim.literal]

A - это первичное выражение. Его тип зависит от его . Строковый литерал - это lvalue; все остальные литералы являются prvalue.literal form

8.1.2 This [expr.prim.this]

Ключевое слово this именует указатель на объект, для которого вызывается нестатическая функция-член или[class.mem]оценивается инициализатор ( ) нестатического элемента данных .

Если объявление объявляет функцию-член или шаблон функции-члена класса X, выражение this представляет собой prvalue типа «указатель на cv-qualifier-seq X» между необязательным cv-qualifier-seqи концом function-definition, member-declaratorили declarator. Он не должен появляться перед необязательным cv-qualifier-seqи не должен появляться в объявлении статической функции-члена (хотя ее тип и категория значения определены в статической функции-члене, поскольку они находятся в нестатической функции-члене). [ Note: Это связано с тем, что сопоставление деклараций не происходит до тех пор, пока не будет известен полный декларатор. ] В отличие от объектного выражения в других контекстах, не требуется, чтобы он был полного типа для целей вне тела функции-члена. [ Видны только члены класса, объявленные до объявления. ] [ end note *this class member access Note: end noteExample:

struct A {
  char g();
  template<class T> auto f(T t) -> decltype(t + g())
    { return t + g(); }
};
template auto A::f(int t) -> decltype(t + g());

end example]

В противном случае, если a member-declaratorобъявляет нестатический data member класс X, выражение this является prvalue типа «указатель на X» внутри необязательного default member initializer. Он не должен появляться где-либо еще в member-declarator.

Выражение this не должно появляться ни в каком другом контексте. [Example:

class Outer {
  int a[sizeof(*this)];               // error: not inside a member function
  unsigned int sz = sizeof(*this);    // OK: in default member initializer

  void f() {
    int b[sizeof(*this)];             // OK

    struct Inner {
      int c[sizeof(*this)];           // error: not inside a member function of Inner
    };
  }
};

end example]

8.1.3 Parentheses [expr.prim.paren]

Выражение в скобках (E) - это основное выражение, тип, значение и категория значения которого идентичны таковым из E. Выражение в скобках может использоваться в тех же контекстах, что и те, в которых оно E может использоваться, и с тем же значением, если не указано иное.

8.1.4 Names [expr.prim.id]

id-expression:
	unqualified-id
	qualified-id

An id-expression- это ограниченная форма primary-expression. [ Может появиться после . ]Note: id-expression. and -> operatorsend note

Можно id-expressionиспользовать только нестатический член данных или нестатическую функцию-член класса:

  • как часть, class member access в которой выражение объекта относится к классу члена65 или классу, производному от этого класса, или

  • чтобы сформировать указатель на member ([expr.unary.op]), или

  • если это id-expressionобозначает нестатический член данных и появляется в неоцененном операнде. [Example:

    struct S {
      int m;
    };
    int i = sizeof(S::m);           // OK
    int j = sizeof(S::m + 42);      // OK
    

    end example]

Это также применимо, когда объектное выражение является неявным (*this) ([class.mfct.non-static]).

8.1.4.1 Unqualified names [expr.prim.id.unqual]

unqualified-id:
	identifier
	operator-function-id
	conversion-function-id
	literal-operator-id
	~ class-name
	~ decltype-specifier
	template-id

identifierПриведено при id-expressionусловии , что было соответствующим образом объявлено (пункт [dcl.dcl]). [ Note: Для получения operator-function-idsсм [over.oper]; для conversion-function-ids, см [class.conv.fct]; для literal-operator-ids, см [over.literal]; для template-ids, см [temp.names]. A class-name или с decltype-specifier префиксом ~ означает деструктор; см [class.dtor]. В определении нестатической функции-члена, identifierимя нестатического члена преобразуется в выражение доступа к члену класса ([class.mfct.non-static]). ] Тип выражения - это тип . Результатом является сущность, обозначенная идентификатором. Выражение является lvalue, если сущность является функцией, переменной или членом данных, и prvalue в противном случае; это битовое поле, если идентификатор обозначает битовое поле ( ).end noteidentifier[dcl.struct.bind]

8.1.4.2 Qualified names [expr.prim.id.qual]

qualified-id:
	nested-name-specifier templateopt unqualified-id

nested-name-specifier:
	::
	type-name ::
	namespace-name ::
	decltype-specifier ::
	nested-name-specifier identifier ::
	nested-name-specifier templateopt simple-template-id ::

Тип, обозначенный a decltype-specifierв a, nested-name-specifierдолжен быть классом или перечислимым типом.

A nested-name-specifier, обозначающий класс, за которым может следовать ключевое слово template ([temp.names]), а затем имя члена этого класса ([class.mem]) или одного из его base classes, - это a ; описывает поиск по имени для членов класса, которые появляются в . Результат - член. Тип результата - это тип члена. Результатом является lvalue, если член является статической функцией-членом или членом данных, и prvalue в противном случае. [К члену класса можно обратиться с помощью a в любой точке его потенциальной области видимости ( ). ] Где используется, оба должны относиться к одному и тому же классу; это обозначение именует . Форма также обозначает деструктор, но она не должна использоваться в качестве элемента в a . [ Имя класса - это ( ). ]qualified-id [class.qual] qualified-idsNote: qualified-id[basic.scope.class]end noteclass-name ​::​~ class-nameclass-names destructor ~ decltype-specifierunqualified-idqualified-idNote: typedef-nameclass-name[class.name]end note

В nested-name-specifier ​::​ именах глобального пространства имен. A, nested-name-specifierкоторый называет пространство имен ([basic.namespace]), за которым необязательно следует ключевое слово template ([temp.names]), а затем следует имя члена этого пространства имен (или имя члена пространства имен, сделанное видимым с помощью a using-directive), является a ; описывает поиск по именам для членов пространства имен, которые появляются в . Результат - член. Тип результата - это тип члена. Результатом является lvalue, если член является функцией или переменной, и prvalue в противном случае.qualified-id [namespace.qual] qualified-ids

A, nested-name-specifierкоторый обозначает enumeration, за которым следует имя перечислителя этого перечисления, является a, qualified-id который ссылается на перечислитель. Результат - счетчик. Тип результата - это тип перечисления. Результат - prvalue.

В a qualified-id, если unqualified-id является a conversion-function-id, он conversion-type-id должен обозначать один и тот же тип как в контексте, в котором qualified-idпроисходит целое, так и в контексте класса, обозначенного nested-name-specifier.

8.1.5 Lambda expressions [expr.prim.lambda]

lambda-expression:
	lambda-introducer lambda-declaratoropt compound-statement
lambda-introducer:
	[ lambda-captureopt ]
lambda-declarator:
	( parameter-declaration-clause ) decl-specifier-seqopt
	noexcept-specifieropt attribute-specifier-seqopt trailing-return-typeopt

Лямбда-выражения обеспечивают краткий способ создания простых функциональных объектов. [Example:

#include <algorithm>
#include <cmath>
void abssort(float* x, unsigned N) {
  std::sort(x, x + N, [](float a, float b) { return std::abs(a) < std::abs(b); });
}

end example]

A lambda-expression- это prvalue, объект результата которого называется closure object. A lambda-expressionне должен появляться в unevaluated operand, в template-argument, в alias-declaration, в объявлении typedef или в объявлении функции или шаблона функции вне ее тела функции и аргументов по умолчанию. [ Note: Цель состоит в том, чтобы предотвратить появление лямбда-выражений в подписи. ] [ Замыкающий объект ведет себя как объект . ]end noteNote: function objectend note

В decl-specifier-seqчасти lambda-declaratorкаждый decl-specifier должен быть mutable либо constexpr.

Если a lambda-expressionне включает a lambda-declarator, это как если бы lambda-declaratorбыло (). Тип возврата лямбда - это auto, который заменяется типом, указанным в trailing-return-typeif, предоставленном и / или выведенном из return операторов, как описано в [dcl.spec.auto]. [Example:

auto x1 = [](int i){ return i; };     // OK: return type is int
auto x2 = []{ return { 1, 2 }; };     // error: deducing return type from braced-init-list
int j;
auto x3 = []()->auto&& { return j; }; // OK: return type is int&

end example]

8.1.5.1 Closure types [expr.prim.lambda.closure]

Тип a lambda-expression(который также является типом закрывающего объекта) - это уникальный безымянный тип класса без объединения, называемый the closure type, свойства которого описаны ниже.

Тип закрытия объявляется в области наименьшего блока, области класса или области имен, которая содержит соответствующий lambda-expression. [ Note: Это определяет набор пространств имен и классов, связанных с типом замыкания ([basic.lookup.argdep]). Типы параметров lambda-declaratorне влияют на эти связанные пространства имен и классы. ] Тип замыкания не является агрегатным типом ( ). Реализация может определять тип закрытия иначе, чем описано ниже, при условии, что это не изменяет наблюдаемое поведение программы, кроме как путем изменения: end note[dcl.init.aggr]

Реализация не должна добавлять элементы ссылочного типа rvalue к типу закрытия.

Тип закрытия для неуниверсального типа lambda-expressionимеет общедоступную встроенную строку function call operator , параметры и возвращаемый тип которой описываются lambda-expressionсимволами parameter-declaration-clauseи trailing-return-type соответственно. Для общей лямбды тип замыкания имеет общедоступный встроенный оператор вызова функции member template , который template-parameter-listсостоит из одного придуманного типа template-parameterдля каждого вхождения auto в лямбда parameter-declaration-clauseв порядке появления. Изобретенный тип template-parameter- это пакет параметров, если соответствующий parameter-declarationобъявляет функцию параметра pack ([dcl.fct]). Тип возвращаемого значения и параметры функции шаблона оператора вызова функции являются производными от lambda-expression's trailing-return-typeи parameter-declaration-clauseпутем замены каждого вхождения auto в decl-specifiers the parameter-declaration-clauseна имя соответствующего изобретенного template-parameter. [Example:

auto glambda = [](auto a, auto&& b) { return a < b; };
bool b = glambda(3, 3.14);                             // OK

auto vglambda = [](auto printer) {
  return [=](auto&& ... ts) {                          // OK: ts is a function parameter pack
    printer(std::forward<decltype(ts)>(ts)...);

    return [=]() {
      printer(ts ...);
    };
  };
};
auto p = vglambda( [](auto v1, auto v2, auto v3)
                   { std::cout << v1 << v2 << v3; } );
auto q = p(1, 'a', 3.14);                              // OK: outputs 1a3.14
q();                                                   // OK: outputs 1a3.14

end example]

Оператор вызова функции или шаблон оператора объявляется const ([class.mfct.non-static]) тогда и только тогда, когда за lambda-expression's parameter-declaration-clauseне следует mutable. Он не виртуальный и не декларируемый volatile. Любое noexcept-specifierуказанное в a lambda-expression применяется к соответствующему оператору вызова функции или шаблону оператора. В attribute-specifier-seqa lambda-declaratorпринадлежит типу соответствующего оператора вызова функции или шаблона оператора. Оператор вызова функции или любая заданная специализация шаблона оператора является функцией constexpr, если либо за соответствующими lambda-expression's parameter-declaration-clauseследуют constexpr, либо если она удовлетворяет требованиям для constexpr функции. [ Note: Имена, упомянутые в lambda-declarator, ищутся в контексте, в котором lambda-expressionпоявляется. ] [ end noteExample:

auto ID = [](auto a) { return a; };
static_assert(ID(3) == 3); // OK

struct NonLiteral {
  NonLiteral(int n) : n(n) { }
  int n;
};
static_assert(ID(NonLiteral{3}).n == 3); // ill-formed

end example]

[Example:

auto monoid = [](auto v) { return [=] { return v; }; };
auto add = [](auto m1) constexpr {
  auto ret = m1();
  return [=](auto m2) mutable {
    auto m1val = m1();
    auto plus = [=](auto m2val) mutable constexpr
                   { return m1val += m2val; };
    ret = plus(m2());
    return monoid(ret);
  };
};
constexpr auto zero = monoid(0);
constexpr auto one = monoid(1);
static_assert(add(one)(zero)() == one()); // OK

// Since two below is not declared constexpr, an evaluation of its constexpr member function call operator
// cannot perform an lvalue-to-rvalue conversion on one of its subobjects (that represents its capture)
// in a constant expression.
auto two = monoid(2);
assert(two() == 2); // OK, not a constant expression.
static_assert(add(one)(one)() == two()); // ill-formed: two() is not a constant expression
static_assert(add(one)(one)() == monoid(2)()); // OK

end example]

Тип закрытия для неуниверсального типа lambda-expressionс no lambda-capture имеет функцию преобразования в указатель на функцию с языком C ++, linkage имеющую тот же параметр и возвращаемые типы, что и оператор вызова функции типа закрытия. Преобразование происходит в «указатель на noexcept функцию», если оператор вызова функции имеет спецификацию исключения, не вызывающего выброса. Значение, возвращаемое этой функцией преобразования, является адресом функции, F которая при вызове имеет тот же эффект, что и вызов оператора вызова функции закрывающего типа. F является функцией constexpr, если оператор вызова функции является функцией constexpr. Для общей лямбды без no lambda-captureтип закрытия имеет шаблон функции преобразования в указатель на функцию. Шаблон функции преобразования изобретен так же template-parameter-list, а указатель на функцию имеет те же типы параметров, что и шаблон оператора вызова функции. Тип возвращаемого значения указателя на функцию должен вести себя так, как если бы он был decltype-specifierобозначением типа возвращаемого значения соответствующей специализации шаблона оператора вызова функции.

[ Note: Если универсальная лямбда не имеет типа заполнителя trailing-return-typeили trailing-return-typeсодержит тип-заполнитель, необходимо вывести тип возвращаемого значения соответствующей специализации шаблона оператора вызова функции. Соответствующей специализацией является создание экземпляра шаблона оператора вызова функции с теми же аргументами шаблона, что и выведенные для шаблона функции преобразования. Учтите следующее:

auto glambda = [](auto a) { return a; };
int (*fp)(int) = glambda;

Поведение glambda вышеупомянутой функции преобразования похоже на поведение следующей функции преобразования:

struct Closure {
  template<class T> auto operator()(T t) const { ... }
  template<class T> static auto lambda_call_operator_invoker(T a) {
    // forwards execution to operator()(a) and therefore has
    // the same return type deduced
    ...
  }
  template<class T> using fptr_t =
     decltype(lambda_call_operator_invoker(declval<T>())) (*)(T);

  template<class T> operator fptr_t<T>() const
    { return &lambda_call_operator_invoker; }
};

end note]

[Example:

void f1(int (*)(int))   { }
void f2(char (*)(int))  { }

void g(int (*)(int))    { }  // #1
void g(char (*)(char))  { }  // #2

void h(int (*)(int))    { }  // #3
void h(char (*)(int))   { }  // #4

auto glambda = [](auto a) { return a; };
f1(glambda);  // OK
f2(glambda);  // error: ID is not convertible
g(glambda);   // error: ambiguous
h(glambda);   // OK: calls #3 since it is convertible from ID
int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK

end example]

Значение, возвращаемое любой данной специализацией этого шаблона функции преобразования, является адресом функции, F которая при вызове имеет тот же эффект, что и вызов соответствующей специализации шаблона оператора вызова функции универсальной лямбды. F является функцией constexpr, если соответствующая специализация является функцией constexpr. [ Note: Это приведет к неявной реализации тела универсальной лямбды. Тип возвращаемого значения и типы параметров созданного универсального лямбда-выражения должны соответствовать типу возвращаемого значения и типам параметров указателя на функцию. ] [end noteExample:

auto GL = [](auto a) { std::cout << a; return a; };
int (*GL_int)(int) = GL;  // OK: through conversion function template
GL_int(3);                // OK: same as GL(3)

end example]

Функция преобразования или шаблон функции преобразования являются общедоступными, constexpr, не виртуальными, неявными, константными и имеют не-бросание exception specification. [Example:

auto Fwd = [](int (*fp)(int), auto a) { return fp(a); };
auto C = [](auto a) { return a; };

static_assert(Fwd(C,3) == 3); // OK

// No specialization of the function call operator template can be constexpr (due to the local static).
auto NC = [](auto a) { static int s; return a; };
static_assert(Fwd(NC,3) == 3); // ill-formed

end example]

В lambda-expression«S compound-statementдает function-body([dcl.fct.def]) оператор вызова функции, но для целей name lookup, определяющего типа и значение ,this и преобразующей со id-expressions ссылкой на нестатические член класса в выражения доступа членов класса с использованием (*this) ([class.mfct.non-static]), то compound-statementрассматривается в контексте lambda-expression. [Example:

struct S1 {
  int x, y;
  int operator()(int);
  void f() {
    [=]()->int {
      return operator()(this->x + y); // equivalent to S1​::​operator()(this->x + (*this).y)
                                      // this has type S1*
    };
  }
};

end example] Кроме того, переменная _­_­func_­_­ неявно определяется в начале compound-statementиз lambda-expression, с семантикой , как описано в [dcl.fct.def.general].

Тип закрытия, связанный с a, lambda-expressionне имеет конструктора по умолчанию и оператора присваивания удаленной копии. Он имеет конструктор копирования по умолчанию и конструктор перемещения по умолчанию ([class.copy]). [ Note: Эти специальные функции-члены неявно определены как обычно и поэтому могут быть определены как удаленные. ] end note

Тип закрытия, связанный с a, lambda-expressionимеет неявно объявленный деструктор ([class.dtor]).

Член закрывающего типа не должен быть явно создан ([temp.explicit]), явно специализирован ([temp.expl.spec]) или назван в friend объявлении ([class.friend]).

8.1.5.2 Captures [expr.prim.lambda.capture]

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* thisNote: [&,this] end noteinitializers init-capturesthis lambda-captureExample:

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 a local 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 noteExample:

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-uses this (в случае объекта, обозначенного *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(см. Ниже). Неявное использование odr this может привести к неявному захвату. ] end note

Сущность - captured это если она захвачена явно или неявно. Сущность, захваченная объектом, lambda-expressionнаходится odr-used в области, содержащей lambda-expression. Если *this он захвачен локальным лямбда-выражением, его ближайшая включающая функция должна быть нестатической функцией-членом. Если a lambda-expressionили создание экземпляра шаблона оператора вызова функции универсальной лямбда-выражения odr-uses this или переменной с автоматической продолжительностью хранения из достигаемой области действия, этот объект должен быть захвачен 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 если

Для каждой сущности, захваченной копией, в типе замыкания объявляется безымянный нестатический член данных. Порядок объявления этих членов не указан. Тип такого члена данных - это ссылочный тип, если сущность является ссылкой на объект, ссылка lvalue на ссылочный тип функции, если сущность является ссылкой на функцию, или тип соответствующей захваченной сущности в противном случае. Член анонимного союза не может быть записан копией.

Каждый элемент id-expressionвнутри compound-statementa, lambda-expressionкоторый является odr-use сущностью, захваченной копией, преобразуется в доступ к соответствующему безымянному элементу данных типа закрытия. [ , Что не является ODR использование относится к оригинальной сущности, никогда не члену типа закрытия. Более того, такое не вызывает неявного захвата объекта. ] Если захватывается копией, каждое использование odr преобразуется в указатель на соответствующий безымянный элемент данных типа замыкания, на тип . [ Приведение гарантирует, что преобразованное выражение является prvalue. ] Элемент внутри элемента a, который является случайным использованием ссылки, захваченной посредством ссылки, относится к объекту, к которому привязана захваченная ссылка, а не к захваченной ссылке. [ Действительность таких захватов определяется временем жизни объекта, на который ссылается ссылка, а не временем жизни самой ссылки. ] [Note: id-expressionid-expression end note *this this cast thisNote: end noteid-expressioncompound-statementlambda-expressionNote: end noteExample:

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-expression m2 захватывает сущность, и эта сущность захватывается немедленным включением 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]

8.1.6 Fold expressions [expr.prim.fold]

Выражение свертки выполняет свертку template parameter pack над бинарным оператором.

fold-expression:
	( cast-expression fold-operator ... )
	( ... fold-operator cast-expression )
	( cast-expression fold-operator ... fold-operator cast-expression )
fold-operator: one of
	+   -   *   /   %   ^   &   |   <<   >> 
	+=  -=  *=  /=  %=  ^=  &=  |=  <<=  >>=  =
	==  !=  <   >   <=  >=  &&  ||  ,    .*   ->*

Выражение формы, (... op e) где op есть a fold-operator , называется a unary left fold. Выражение формы, (e op ...) где op есть a fold-operator , называется a unary right fold. Унарные левые складки и унарные правые складки называются вместе unary folds. В унарном сгибе cast-expression должен содержать unexpanded parameter pack.

Выражение формы (e1 op1 ... op2 e2) where op1 и op2 are fold-operators называется a binary fold. В двоичной свертке, op1 и op2 должны быть одинаковыми fold-operator, и либо e1 должен содержать нерасширенный пакет параметров, либо e2 должен содержать нерасширенный пакет параметров, но не оба вместе. Если e2 содержит нерасширенный пакет параметров, выражение называется binary left fold. Если e1 содержит нерасширенный пакет параметров, выражение называется binary right fold. [Example:

template<typename ...Args>
bool f(Args ...args) {
  return (true && ... && args); // OK
}

template<typename ...Args>
bool f(Args ...args) {
  return (args + ... + args);   // error: both operands contain unexpanded parameter packs
}

end example]