[expr.prim] (original) (raw)

7 Expressions [expr]

7.5 Primary expressions [expr.prim]

7.5.3 This [expr.prim.this]

The keyword this names a pointer to the object for which an implicit object member function ([class.mfct.non.static]) is invoked or a non-static data member's initializer ([class.mem]) is evaluated.

The current class at a program point is the class associated with the innermost class scope containing that point.

[Note 1:

A lambda-expression does not introduce a class scope.

— _end note_]

If the expression thisappears within the predicate of a contract assertion ([basic.contract.general]) (including as the result of an implicit transformation ([expr.prim.id.general]) and including in the bodies of nested lambda-expressions) and the current class encloses the contract assertion,const is combined with the cv-qualifier-seqused to generate the resulting type (see below).

It shall not appear within the declaration of a static or explicit object member function of the current class (although its type and value category are defined within such member functions as they are within an implicit object member function).

[Note 2:

This is because declaration matching does not occur until the complete declarator is known.

— _end note_]

[Note 3:

Class members declared later are not visible.

[Example 1: 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_]

— _end note_]

Otherwise, if a member-declarator declares a non-static data member ([class.mem]) of a class X, the expression this is a prvalue of type “pointer to X” wherever X is the current class within the optional default member initializer ([class.mem]).

The expression this shall not appear in any other context.

[Example 2: class Outer { int a[sizeof(*this)]; unsigned int sz = sizeof(*this); void f() { int b[sizeof(*this)]; struct Inner { int c[sizeof(*this)]; };} }; — _end example_]

7.5.4 Parentheses [expr.prim.paren]

A parenthesized expression (E)is a primary expression whose type, result, and value category are identical to those of E.

The parenthesized expression can be used in exactly the same contexts as those where E can be used, and with the same meaning, except as otherwise indicated.

7.5.5 Names [expr.prim.id]

7.5.5.1 General [expr.prim.id.general]

An id-expression is a restricted form of aprimary-expression.

If an id-expression E denotes a non-static non-type member of some class C at a point where the current class ([expr.prim.this]) is X and

the id-expression is transformed into a class member access expression using (*this) as the object expression.

If this transformation occurs in the predicate of a precondition assertion of a constructor of Xor a postcondition assertion of a destructor of X, the expression is ill-formed.

[Note 2:

If C is not X or a base class of X, the class member access expression is ill-formed.

Also, if the id-expression occurs within a static or explicit object member function, the class member access is ill-formed.

— _end note_]

This transformation does not apply in the template definition context ([temp.dep.type]).

[Example 1: struct C { bool b; C() pre(b) pre(&this->b) pre(sizeof(b) > 0); }; — _end example_]

If an id-expression E denotes a member M of an anonymous union ([class.union.anon]) U:

An id-expression that denotes a non-static data member or implicit object member function of a class can only be used:

For an id-expression that denotes an overload set, overload resolution is performed to select a unique function ([over.match], [over.over]).

[Note 4:

A program cannot refer to a function with a trailing requires-clausewhose constraint-expression is not satisfied, because such functions are never selected by overload resolution.

[Example 5: template<typename T> struct A { static void f(int) requires false;};void g() { A<int>::f(0); void (*p1)(int) = A<int>::f; decltype(A<int>::f)* p2 = nullptr; }

In each case, the constraints of f are not satisfied.

In the declaration of p2, those constraints need to be satisfied even thoughf is an unevaluated operand.

— _end example_]

— _end note_]

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

The terminal name of a construct is the component name of that construct that appears lexically last.

If

then the type of the expression is the type of a class member access expression ([expr.ref]) naming the non-static data member that would be declared for such a capture in the object parameter ([dcl.fct]) of the function call operator of E.

[Note 3:

If E is not declared mutable, the type of such an identifier will typically be const qualified.

— _end note_]

Otherwise, if the unqualified-idnames a coroutine parameter, the type of the expression is that of the copy of the parameter ([dcl.fct.def.coroutine]), and the result is that copy.

Otherwise, if the unqualified-idnames a result binding ([dcl.contract.res]) attached to a function _f_with return type U,

Otherwise, if the unqualified-idappears in the predicate of a contract assertion C ([basic.contract]) and the entity is

then the type of the expression is const T.

[Example 1: int n = 0;struct X { bool m(); };struct Y { int z = 0;void f(int i, int* p, int& r, X x, X* px) pre (++n) pre (++i) pre (++(*p)) pre (++r) pre (x.m()) pre (px->m()) pre ([=,&i,*this] mutable { ++n; ++i; ++p; ++r; ++this->z; ++z; int j = 17;[&]{ int k = 34;++i; ++j; ++k; }();return true;}());template <int N, int& R, int* P> void g() pre(++N) pre(++R) pre(++(*P)); int h() post(r : ++r) post(r: [=] mutable { ++r; return true;}());int& k() post(r : ++r); }; — _end example_]

Otherwise, if the entity is a template parameter object for a template parameter of type T ([temp.param]), the type of the expression is const T.

In all other cases, the type of the expression is the type of the entity.

[Note 4:

The type will be adjusted as described in [expr.type]if it is cv-qualified or is a reference type.

— _end note_]

The expression is an xvalue if it is move-eligible (see below); an lvalue if the entity is a function, variable, structured binding ([dcl.struct.bind]), result binding ([dcl.contract.res]), data member, or template parameter object; and a prvalue otherwise ([basic.lval]); it is a bit-field if the identifier designates a bit-field.

If an id-expression Eappears in the predicate of a function contract assertion attached to a function _f_and denotes a function parameter of _f_and the implementation introduces any temporary objects to hold the value of that parameter as specified in [class.temporary],

If an id-expression Enames a result binding in a postcondition assertion and the implementation introduces any temporary objects to hold the result object as specified in [class.temporary], and the postcondition assertion is sequenced before the initialization of the result object ([expr.call]),E refers to the most recently initialized such temporary object.

[Example 2: void f() { float x, &r = x;[=]() -> decltype((x)) { decltype(x) y1; decltype((x)) y2 = y1; decltype(r) r1 = y1; decltype((r)) r2 = y2; return y2;};[=](decltype((x)) y) { decltype((x)) z = x; };[=] { [](decltype((x)) y) {}; [x=1](decltype((x)) y) { decltype((x)) z = x; };};} — _end example_]

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

The component names of a qualified-id are those of its nested-name-specifier and unqualified-id.

A declaration that uses a declarative nested-name-specifiershall be a friend declaration or inhabit a scope that contains the entity being redeclared or specialized.

The nested-name-specifier ​::​ nominates the global namespace.

If a nested-name-specifier Nis declarative and has a simple-template-id with a template argument list Athat involves a template parameter, let T be the template nominated by N without A.

T shall be a class template.

If the nested-name-specifier is not declarative, the entity shall not be a template.

If Q appears in the predicate of a contract assertion C ([basic.contract]) and the entity is

then the type of the expression is const T.

Otherwise, the type of the expression is the type of the result.

The result is an lvalue if the member is

and a prvalue otherwise.

7.5.5.5 Destruction [expr.prim.id.dtor]

An id-expression that denotes the destructor of a type Tnames the destructor of Tif T is a class type ([class.dtor]), otherwise the id-expression is said to name a pseudo-destructor.

[Example 1: struct C { };void f() { C * pc = new C;using C2 = C; pc->C::~C2(); C().C::~C(); using T = int;0 .T::~T(); 0.T::~T(); } — _end example_]

7.5.6 Lambda expressions [expr.prim.lambda]

7.5.6.1 General [expr.prim.lambda.general]

lambda-specifier:
consteval
constexpr
mutable
static

A lambda-expression provides a concise way to create a simple function object.

[Example 1: #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 is a prvalue whose result object is called the closure object.

[Note 2:

Such ambiguous cases cannot have valid semantics because the constraint expression would not have type bool.

[Example 2: auto x = []<class T> requires T::operator int [[some_attribute]] (int) { } — _end example_]

— _end note_]

A lambda-specifier-seqshall contain at most one of each lambda-specifier and shall not contain both constexpr and consteval.

If the lambda-declarator contains an explicit object parameter ([dcl.fct]), then no lambda-specifier in the lambda-specifier-seqshall be mutable or static.

The lambda-specifier-seq shall not contain both mutable and static.

If the lambda-specifier-seq contains static, there shall be no lambda-capture.

[Note 4:

In that case, the return type is deduced from return statements as described in [dcl.spec.auto].

— _end note_]

[Example 3: auto x1 = [](int i) { return i; }; auto x2 = []{ return { 1, 2 }; }; int j;auto x3 = [&]()->auto&& { return j; }; — _end example_]

[Example 4: auto x = [](int i, auto a) { return i; }; auto y = [](this auto self, int i) { return i; }; auto z = []<class T>(int i) { return i; }; — _end example_]

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

The type of a lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union class type, called the closure type, whose properties are described below.

The closure type is declared in the smallest block scope, class scope, or namespace scope that contains the correspondinglambda-expression.

[Note 1:

This determines the set of namespaces and classes associated with the closure type ([basic.lookup.argdep]).

The parameter types of a lambda-declarator do not affect these associated namespaces and classes.

— _end note_]

The closure type is not an aggregate type ([dcl.init.aggr]); it is a structural type ([temp.param]) if and only if the lambda has no lambda-capture.

An implementation may define the closure type differently from what is described below provided this does not alter the observable behavior of the program other than by changing:

An implementation shall not add members of rvalue reference type to the closure type.

[Note 2:

The function call operator template for a generic lambda can be an abbreviated function template ([dcl.fct]).

— _end note_]

[Example 1: auto glambda = [](auto a, auto&& b) { return a < b; };bool b = glambda(3, 3.14); auto vglambda = [](auto printer) { return [=](auto&& ... ts) { 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); q(); auto fact = [](this auto self, int n) -> int { return (n <= 1) ? 1 : n * self(n-1);}; std::cout << fact(5); — _end example_]

Given a lambda with a lambda-capture, the type of the explicit object parameter, if any, of the lambda's function call operator (possibly instantiated from a function call operator template) shall be either:

[Example 2: struct C { template <typename T> C(T);};void func(int i) { int x = [=](this auto&&) { return i; }(); int y = [=](this C) { return i; }(); int z = [](this C) { return 42; }(); } — _end example_]

The function call operator or operator template is a static member function or static member function template ([class.static.mfct]) if the lambda-expression'sparameter-declaration-clause is followed by static.

It is neither virtual nor declared volatile.

An attribute-specifier-seq in a lambda-declarator appertains to the type of the corresponding function call operator or operator template.

An attribute-specifier-seq in a lambda-expressionpreceding a lambda-declaratorappertains to the corresponding function call operator or operator template.

The function call operator or any given operator template specialization is a constexpr function if either the corresponding lambda-expression'sparameter-declaration-clauseis followed by constexpr or consteval, or it is constexpr-suitable ([dcl.constexpr]).

[Example 3: auto ID = [](auto a) { return a; };static_assert(ID(3) == 3); struct NonLiteral { NonLiteral(int n) : n(n) { } int n;};static_assert(ID(NonLiteral{3}).n == 3); — _end example_]

[Example 4: 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()); auto two = monoid(2); assert(two() == 2); static_assert(add(one)(one)() == two()); static_assert(add(one)(one)() == monoid(2)()); — _end example_]

[Note 3:

[Example 5: template <typename T> concept C1 = ;template <std::size_t N> concept C2 = ;template <typename A, typename B> concept C3 = ;auto f = []<typename T1, C1 T2> requires C2<sizeof(T1) + sizeof(T2)> (T1 a1, T1 b1, T2 a2, auto a3, auto a4) requires C3<decltype(a4), T2> { }; — _end example_]

— _end note_]

If all potential references to a local entity implicitly captured by a lambda-expression Loccur within the function contract assertions ([dcl.contract.func]) of the call operator or operator template of Lor within assertion-statements ([stmt.contract.assert]) within the body of L, the program is ill-formed.

[Note 4:

Adding a contract assertion to an existing C++ program cannot cause additional captures.

— _end note_]

[Example 6: static int i = 0;void test() { auto f1 = [=] pre(i > 0) {}; int i = 1;auto f2 = [=] pre(i > 0) {}; auto f3 = [i] pre(i > 0) {}; auto f4 = [=] { contract_assert(i > 0); };auto f5 = [=] { contract_assert(i > 0); (void)i;};auto f6 = [=] pre( []{ bool x = true;return [=]{ return x; }(); }()) {};bool y = true;auto f7 = [=] pre([=]{ return y; }()); } — _end example_]

The closure type for a non-generic lambda-expression with nolambda-captureand no explicit object parameter ([dcl.fct]) whose constraints (if any) are satisfied has a conversion function to pointer to function with C++ language linkage having the same parameter and return types as the closure type's function call operator.

The conversion is to “pointer to noexcept function” if the function call operator has a non-throwing exception specification.

If the function call operator is a static member function, then the value returned by this conversion function is a pointer to the function call operator.

Otherwise, the value returned by this conversion function is a pointer to a function F that, when invoked, has the same effect as invoking the closure type's function call operator on a default-constructed instance of the closure type.

F is a constexpr function if the function call operator is a constexpr function and is an immediate function if the function call operator is an immediate function.

For a generic lambda with no lambda-captureand no explicit object parameter ([dcl.fct]), the closure type has a conversion function template to pointer to function.

The conversion function template has the same invented template parameter list, and the pointer to function has the same parameter types, as the function call operator template.

The return type of the pointer to function shall behave as if it were adecltype-specifier denoting the return type of the corresponding function call operator template specialization.

[Note 5:

If the generic lambda has no trailing-return-type or the trailing-return-type contains a placeholder type, return type deduction of the corresponding function call operator template specialization has to be done.

The corresponding specialization is that instantiation of the function call operator template with the same template arguments as those deduced for the conversion function template.

Consider the following:auto glambda = [](auto a) { return a; };int (*fp)(int) = glambda;

The behavior of the conversion function of glambda above is like that of the following conversion function:struct Closure { template<class T> auto operator()(T t) const { } template<class T> static auto lambda_call_operator_invoker(T a) { } 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 7: void f1(int (*)(int)) { } void f2(char (*)(int)) { } void g(int (*)(int)) { } void g(char (*)(char)) { } void h(int (*)(int)) { } void h(char (*)(int)) { } auto glambda = [](auto a) { return a; }; f1(glambda); f2(glambda); g(glambda); h(glambda); int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; — _end example_]

If the function call operator template is a static member function template, then the value returned by any given specialization of this conversion function template is a pointer to the corresponding function call operator template specialization.

Otherwise, the value returned by any given specialization of this conversion function template is a pointer to a function F that, when invoked, has the same effect as invoking the generic lambda's corresponding function call operator template specialization on a default-constructed instance of the closure type.

F is a constexpr function if the corresponding specialization is a constexpr function andF is an immediate function if the function call operator template specialization is an immediate function.

[Note 6:

This will result in the implicit instantiation of the generic lambda's body.

The instantiated generic lambda's return type and parameter types need to match the return type and parameter types of the pointer to function.

— _end note_]

[Example 8: auto GL = [](auto a) { std::cout << a; return a; };int (*GL_int)(int) = GL; GL_int(3); — _end example_]

The conversion function or conversion function template is public, constexpr, non-virtual, non-explicit, const, and has a non-throwing exception specification.

[Example 9: auto Fwd = [](int (*fp)(int), auto a) { return fp(a); };auto C = [](auto a) { return a; };static_assert(Fwd(C,3) == 3); auto NC = [](auto a) { static int s; return a; };static_assert(Fwd(NC,3) == 3); — _end example_]

[Example 10: struct S1 { int x, y;int operator()(int);void f() { [=]()->int { return operator()(this->x + y); };} }; — _end example_]

The closure type associated with a lambda-expression has no default constructor if the lambda-expression has a lambda-captureand a defaulted default constructor otherwise.

It has a defaulted copy constructor and a defaulted move constructor ([class.copy.ctor]).

It has a deleted copy assignment operator if the lambda-expressionhas a lambda-capture and defaulted copy and move assignment operators otherwise ([class.copy.assign]).

[Note 7:

These special member functions are implicitly defined as usual, which can result in them being defined as deleted.

— _end note_]

The closure type associated with a lambda-expression has an implicitly-declared destructor ([class.dtor]).

7.5.6.3 Captures [expr.prim.lambda.capture]

The body of a lambda-expression may refer to local entities of enclosing 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 thatlambda-capture shall be preceded by &.

If a lambda-capture includes acapture-default that is =, eachsimple-capture of that lambda-capture shall be of the form “& identifier ...”, “this”, or “* this”.

[Note 1:

The form [&,this] is redundant but accepted for compatibility with C++ 2014.

— _end note_]

Ignoring appearances ininitializers of init-captures, an identifier orthis shall not appear more than once in alambda-capture.

[Example 1: struct S2 { void f(int i); };void S2::f(int i) { [&, i]{ }; [&, this, i]{ }; [&, &i]{ }; [=, *this]{ }; [=, this]{ }; [i, i]{ }; [this, *this]{ }; } — _end example_]

A lambda-expression shall not have a capture-default or simple-capturein its lambda-introducerunless

The simple-captures this and * thisdenote the local entity *this.

An entity that is designated by asimple-captureis said to be explicitly captured.

[Example 2: void f() { int x = 0;auto g = [x](int x) { return 0; }; auto h = [y = 0]<typename y>(y) { return 0; }; } — _end example_]

An init-capture without ellipsis behaves as if it declares and explicitly captures a variable of the form “auto init-capture ;”, except that:

[Note 2:

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 3: int x = 4;auto y = [&r = x, x = x+1]()->int { r += 2;return x+2;}(); auto z = [a = 42](int a) { return 1; }; auto counter = [i=0]() mutable -> decltype(i) { return i++;}; — _end example_]

For the purposes of lambda capture, an expression potentially references local entities as follows:

If an expression potentially references a local entity within a scope in which it is odr-usable ([basic.def.odr]), and the expression would be potentially evaluated if the effect of any enclosing typeid expressions ([expr.typeid]) were ignored, the entity is said to be implicitly capturedby each intervening lambda-expression with an associatedcapture-default that does not explicitly capture it.

The implicit capture of *this is deprecated when thecapture-default is =; see [depr.capture.this].

[Example 4: 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 g1 = [=](auto a) { f(x); };auto g2 = [=](auto a) { int selector[sizeof(a) == 1 ? 1 : 2]{}; f(x, selector); };auto g3 = [=](auto a) { typeid(a + x); };}

Within g1, an implementation can optimize away the capture of x as it is not odr-used.

— _end example_]

[Note 4:

The set of captured entities is determined syntactically, and entities are implicitly captured even if the expression denoting a local entity is within a discarded statement ([stmt.if]).

[Example 5: template<bool B> void f(int n) { [=](auto a) { if constexpr (B && sizeof(a) > 4) { (void)n; } }(0);} — _end example_]

— _end note_]

An entity is captured if it is captured explicitly or implicitly.

[Note 5:

As a consequence, if a lambda-expressionexplicitly captures an entity that is not odr-usable, the program is ill-formed ([basic.def.odr]).

— _end note_]

[Example 6: 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_]

[Note 6:

Because local entities are not odr-usable within a default argument ([basic.def.odr]), a lambda-expression appearing in a default argument cannot implicitly or explicitly capture any local entity.

Such a lambda-expressioncan still have an init-capture if any full-expression in its initializersatisfies the constraints of an expression appearing in a default argument ([dcl.fct.default]).

— _end note_]

[Example 7: 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; })()); void g6(int = ([x=1]{ return x; })()); void g7(int = ([x=i]{ return x; })()); } — _end example_]

An entity is captured by copy if

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 alambda-expression that is an odr-use ([basic.def.odr]) of an entity captured by copy is transformed into an access to the corresponding unnamed data member of the closure type.

[Note 7:

An id-expression that is not an odr-use refers to the original entity, never to a member of the closure type.

However, such an id-expression can still cause the implicit capture of the entity.

— _end note_]

If *this is captured by copy, each expression that odr-uses *this is transformed to instead refer to the corresponding unnamed data member of the closure type.

[Example 8: void f(const int*);void g() { const int N = 10;[=] { int arr[N]; f(&N); };} — _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 9: 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.

An id-expression within the compound-statement of a lambda-expressionthat 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 8:

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 10: auto h(int &r) { return [&] { ++r; };} — _end example_]

If a lambda-expression m2 captures an entity and that entity is captured by an immediately enclosing lambda-expression m1, thenm2's capture is transformed as follows:

[Example 11:

The nested lambda-expressions and invocations below will output123234.

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_]

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 theinit-captures are initialized as indicated by the correspondinginitializer (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 9:

This ensures that the destructions will occur in the reverse order of the constructions.

— _end note_]

[Note 10:

If a non-reference entity is implicitly or explicitly captured by reference, invoking the function call operator of the corresponding lambda-expressionafter the lifetime of the entity has ended is likely to result in undefined behavior.

— _end note_]

An init-capture containing an ellipsis is a pack expansion that declares aninit-capture pack ([temp.variadic]).

[Example 12: template<class... Args> void f(Args... args) { auto lm = [&, args...] { return g(args...); }; lm();auto lm2 = [...xs=std::move(args)] { return g(xs...); }; lm2();} — _end example_]

7.5.7 Fold expressions [expr.prim.fold]

A fold expression performs a fold of a pack ([temp.variadic]) over a binary operator.

fold-operator: one of

An expression of the form(... op e)where op is a fold-operatoris called a unary left fold.

An expression of the form(e op ...)where op is a fold-operatoris called a unary right fold.

Unary left folds and unary right folds are collectively called unary folds.

An expression of the form(e1 op1 ... op2 e2)where op1 and op2 are fold-operator_s_is called a binary fold.

In a binary fold,op1 and _op2_shall be the same fold-operator, and either e1shall contain an unexpanded pack or e2shall contain an unexpanded pack, but not both.

If e2 contains an unexpanded pack, the expression is called a binary left fold.

If e1 contains an unexpanded pack, the expression is called a binary right fold.

[Example 1: template<typename ...Args> bool f(Args ...args) { return (true && ... && args); } template<typename ...Args> bool f(Args ...args) { return (args + ... + args); } — _end example_]

A fold expression is a pack expansion.

7.5.8 Requires expressions [expr.prim.req]

7.5.8.1 General [expr.prim.req.general]

A requires-expression provides a concise way to express requirements on template arguments that can be checked by name lookupor by checking properties of types and expressions.

A requires-expression is a prvalue of type boolwhose value is described below.

[Example 1:

A common use of requires-expressions is to define requirements in concepts such as the one below:template<typename T> concept R = requires (T i) { typename T::type;{*i} -> std::convertible_to<const typename T::type&>;};

A requires-expression can also be used in arequires-clause ([temp.pre]) as a way of writing ad hoc constraints on template arguments such as the one below:template<typename T> requires requires (T x) { x + x; } T add(T a, T b) { return a + b; }

The first requires introduces therequires-clause, and the second introduces the requires-expression.

— _end example_]

A local parameter of a requires-expression shall not have a default argument.

The type of such a parameter is determined as specified for a function parameter in [dcl.fct].

These parameters have no linkage, storage, or lifetime; they are only used as notation for the purpose of defining requirements.

[Example 2: template<typename T> concept C = requires(T t, ...) { t;};template<typename T> concept C2 = requires(T p[2]) { (decltype(p))nullptr; }; — _end example_]

The substitution of template arguments into a requires-expressioncan result in the formation of invalid types or expressions in the immediate context of its requirements ([temp.deduct.general]) or the violation of the semantic constraints of those requirements.

In such cases, the requires-expression evaluates to false; it does not cause the program to be ill-formed.

The substitution and semantic constraint checking proceeds in lexical order and stops when a condition that determines the result of the requires-expression is encountered.

If substitution (if any) and semantic constraint checking succeed, the requires-expression evaluates to true.

[Note 1:

If a requires-expression contains invalid types or expressions in its requirements, and it does not appear within the declaration of a templated entity, then the program is ill-formed.

— _end note_]

If the substitution of template arguments into a requirementwould always result in a substitution failure, the program is ill-formed; no diagnostic required.

[Example 3: template<typename T> concept C = requires { new decltype((void)T{}); }; — _end example_]

7.5.8.2 Simple requirements [expr.prim.req.simple]

[Note 1:

The enclosing requires-expression will evaluate to falseif substitution of template arguments into the expression fails.

— _end note_]

[Example 1: template<typename T> concept C = requires (T a, T b) { a + b; }; — _end example_]

A requirement that starts with a requires token is never interpreted as a simple-requirement.

[Note 2:

This simplifies distinguishing between a simple-requirementand a nested-requirement.

— _end note_]

7.5.8.3 Type requirements [expr.prim.req.type]

A type-requirement asserts the validity of a type.

The component names of a type-requirement are those of itsnested-name-specifier (if any) and type-name.

[Note 1:

The enclosing requires-expression will evaluate to falseif substitution of template arguments fails.

— _end note_]

[Example 1: template<typename T, typename T::type = 0> struct S;template<typename T> using Ref = T&;template<typename T> concept C = requires { typename T::inner; typename S<T>; typename Ref<T>; }; — _end example_]

7.5.8.4 Compound requirements [expr.prim.req.compound]

Substitution of template arguments (if any) and verification of semantic properties proceed in the following order:

[Example 2: template<typename T> concept C1 = requires(T x) { {x++};};

The compound-requirement in C1requires that x++ is a valid expression.

It is equivalent to the simple-requirement x++;.

template<typename T> concept C2 = requires(T x) { {*x} -> std::same_as<typename T::inner>;};

The compound-requirement in C2requires that *x is a valid expression, that typename T​::​inner is a valid type, and that std​::​same_as<decltype((*x)), typename T​::​inner> is satisfied.

template<typename T> concept C3 = requires(T x) { {g(x)} noexcept;};

The compound-requirement in C3requires that g(x) is a valid expression and that g(x) is non-throwing.

— _end example_]

7.5.8.5 Nested requirements [expr.prim.req.nested]

A nested-requirement can be used to specify additional constraints in terms of local parameters.

[Example 1:

template<typename U> concept C = sizeof(U) == 1;template<typename T> concept D = requires (T t) { requires C<decltype (+t)>;}; D<T> is satisfied if sizeof(decltype (+t)) == 1 ([temp.constr.atomic]).

— _end example_]