diff --git a/source/basic.tex b/source/basic.tex index a699ecb4a9..a9dbaf4f1d 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -3634,7 +3634,7 @@ has all of the following properties: \begin{itemize} \item it has a trivial destructor, -\item it is either a closure type~(\ref{expr.prim.lambda}), +\item it is either a closure type~(\ref{expr.prim.lambda.closure}), an aggregate type~(\ref{dcl.init.aggr}), or has at least one constexpr constructor or constructor template (possibly inherited~(\ref{namespace.udecl}) from a base class) diff --git a/source/declarations.tex b/source/declarations.tex index 57790e1747..cd46012bee 100644 --- a/source/declarations.tex +++ b/source/declarations.tex @@ -1556,7 +1556,7 @@ from an initializer. The \tcode{auto} \grammarterm{type-specifier} is also used to introduce a function type having a \grammarterm{trailing-return-type} or to -signify that a lambda is a generic lambda (\ref{expr.prim.lambda}). +signify that a lambda is a generic lambda (\ref{expr.prim.lambda.closure}). The \tcode{auto} \grammarterm{type-specifier} is also used to introduce a decomposition declaration (\ref{dcl.decomp}). @@ -1578,7 +1578,7 @@ \grammarterm{decl-specifier}{s} in the \grammarterm{decl-specifier-seq} of a \grammarterm{parameter-declaration} of a \grammarterm{lambda-expression}, the \indextext{generic lambda!definition of}% -lambda is a \term{generic lambda}~(\ref{expr.prim.lambda}). \begin{example} +lambda is a \term{generic lambda}~(\ref{expr.prim.lambda.closure}). \begin{example} \begin{codeblock} auto glambda = [](int i, auto a) { return i; }; // OK: a generic lambda \end{codeblock} diff --git a/source/expressions.tex b/source/expressions.tex index a8f2f7df49..5b84e410b5 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -601,45 +601,6 @@ \terminal{[} lambda-capture\opt{} \terminal{]} \end{bnf} -\begin{bnf} -\nontermdef{lambda-capture}\br - capture-default\br - capture-list\br - capture-default \terminal{,} capture-list -\end{bnf} - -\begin{bnf} -\nontermdef{capture-default}\br - \terminal{\&}\br - \terminal{=} -\end{bnf} - -\begin{bnf} -\nontermdef{capture-list}\br - capture \terminal{...\opt}\br - capture-list \terminal{,} capture \terminal{...\opt} -\end{bnf} - -\begin{bnf} -\nontermdef{capture}\br - simple-capture\br - init-capture -\end{bnf} - -\begin{bnf} -\nontermdef{simple-capture}\br - identifier\br - \terminal{\&} identifier\br - \terminal{this}\br - \terminal{* this} -\end{bnf} - -\begin{bnf} -\nontermdef{init-capture}\br - identifier initializer\br - \terminal{\&} identifier initializer -\end{bnf} - \begin{bnf} \nontermdef{lambda-declarator}\br \terminal{(} parameter-declaration-clause \terminal{)} decl-specifier-seq\opt\br @@ -658,37 +619,6 @@ \end{codeblock} \end{example} -\pnum -In the \grammarterm{decl-specifier-seq} of the \grammarterm{lambda-declarator}, -each \grammarterm{decl-specifier} -shall either be \tcode{mutable} or \tcode{constexpr}. -\begin{example} -\begin{codeblock} -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 \tcode{two} below is not declared \tcode{constexpr}, an evaluation of its \tcode{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: \tcode{two()} is not a constant expression -static_assert(add(one)(one)() == monoid(2)()); // OK -\end{codeblock} -\end{example} - \pnum A \grammarterm{lambda-expression} is a prvalue whose result object is called the \defn{closure object}. A @@ -705,17 +635,43 @@ object~(\ref{function.objects}).\end{note} \pnum -The type of the \grammarterm{lambda-expression} (which is also the type of the -closure object) is a unique, unnamed non-union class type ---- called the \defn{closure type} --- +In the \grammarterm{decl-specifier-seq} of the \grammarterm{lambda-declarator}, +each \grammarterm{decl-specifier} +shall either be \tcode{mutable} or \tcode{constexpr}. + +\pnum +If a \grammarterm{lambda-expression} does not include a +\grammarterm{lambda-declarator}, it is as if the \grammarterm{lambda-declarator} were +\tcode{()}. +The lambda return type is \tcode{auto}, which is replaced by the +type specified by the +\grammarterm{trailing-return-type} if provided and/or deduced from +\tcode{return} statements as described in~\ref{dcl.spec.auto}. +\begin{example} +\begin{codeblock} +auto x1 = [](int i){ return i; }; // OK: return type is \tcode{int} +auto x2 = []{ return { 1, 2 }; }; // error: deducing return type from \grammarterm{braced-init-list} +int j; +auto x3 = []()->auto&& { return j; }; // OK: return type is \tcode{int\&} +\end{codeblock} +\end{example} + +\rSec3[expr.prim.lambda.closure]{Closure types}% + +\pnum +The type of a \grammarterm{lambda-expression} (which is also the type of the +closure object) is a unique, unnamed non-union class type, +called the \defn{closure type}, whose properties are described below. -This class type is not an aggregate type~(\ref{dcl.init.aggr}). + +\pnum The closure type is declared in the smallest block scope, class scope, or namespace scope that contains the corresponding \grammarterm{lambda-expression}. \begin{note} This determines the set of namespaces and classes associated with the closure type~(\ref{basic.lookup.argdep}). The parameter types of a \grammarterm{lambda-declarator} do not affect these associated namespaces and -classes. \end{note} An implementation may define the closure type differently from what +classes. \end{note} The closure type is not an aggregate type~(\ref{dcl.init.aggr}). +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: @@ -733,23 +689,6 @@ An implementation shall not add members of rvalue reference type to the closure type. -\pnum -If a \grammarterm{lambda-expression} does not include a -\grammarterm{lambda-declarator}, it is as if the \grammarterm{lambda-declarator} were -\tcode{()}. -The lambda return type is \tcode{auto}, which is replaced by the -type specified by the -\grammarterm{trailing-return-type} if provided and/or deduced from -\tcode{return} statements as described in~\ref{dcl.spec.auto}. -\begin{example} -\begin{codeblock} -auto x1 = [](int i){ return i; }; // OK: return type is \tcode{int} -auto x2 = []{ return { 1, 2 }; }; // error: deducing return type from \grammarterm{braced-init-list} -int j; -auto x3 = []()->auto&& { return j; }; // OK: return type is \tcode{int\&} -\end{codeblock} -\end{example} - \pnum The closure type for a non-generic \grammarterm{lambda-expression} has a public inline function call operator~(\ref{over.call}) whose parameters and return type @@ -790,7 +729,9 @@ q(); // OK: outputs \tcode{1a3.14} \end{codeblock} \end{example} -This function call operator or operator template is declared + +\pnum +The function call operator or operator template is declared \tcode{const}~(\ref{class.mfct.non-static}) if and only if the \grammarterm{lambda-expression}'s \grammarterm{parameter-declaration-clause} is not followed by \tcode{mutable}. It is neither virtual nor declared \tcode{volatile}. Any @@ -819,6 +760,34 @@ \end{codeblock} \end{example} +\pnum +\begin{example} +\begin{codeblock} +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 \tcode{two} below is not declared \tcode{constexpr}, an evaluation of its \tcode{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: \tcode{two()} is not a constant expression +static_assert(add(one)(one)() == monoid(2)()); // OK +\end{codeblock} +\end{example} + \pnum The closure type for a non-generic \grammarterm{lambda-expression} with no \grammarterm{lambda-capture} @@ -841,6 +810,8 @@ the pointer to function shall behave as if it were a \grammarterm{decltype-specifier} denoting the return type of the corresponding function call operator template specialization. + +\pnum \begin{note} If the generic lambda has no \grammarterm{trailing-return-type} or the \grammarterm{trailing-return-type} contains a placeholder type, return type @@ -891,6 +862,7 @@ \end{codeblock} \end{example} +\pnum The value returned by any given specialization of this conversion function template is the address of a function \tcode{F} that, when invoked, has the same effect as invoking the generic lambda's corresponding function call operator @@ -910,6 +882,7 @@ \end{codeblock} \end{example} +\pnum The conversion function or conversion function template is public, constexpr, non-virtual, non-explicit, const, and has a non-throwing exception specification~(\ref{except.spec}). @@ -952,6 +925,70 @@ the \grammarterm{compound-statement} of the \grammarterm{lambda-expression}, with semantics as described in~\ref{dcl.fct.def.general}. +\pnum +The closure type associated with a \grammarterm{lambda-expression} has no +default constructor and a deleted copy assignment operator. It has a +defaulted copy constructor and a defaulted move constructor~(\ref{class.copy}). +\begin{note} These special member functions are implicitly defined as +usual, and might therefore be defined as deleted. \end{note} + +\pnum +The closure type associated with a \grammarterm{lambda-expression} has an +implicitly-declared destructor~(\ref{class.dtor}). + +\pnum +A member of a closure type shall not be +explicitly instantiated~(\ref{temp.explicit}), +explicitly specialized~(\ref{temp.expl.spec}), or +named in a \tcode{friend} declaration~(\ref{class.friend}). + +\rSec3[expr.prim.lambda.capture]{Captures}% + +\begin{bnf} +\nontermdef{lambda-capture}\br + capture-default\br + capture-list\br + capture-default \terminal{,} capture-list +\end{bnf} + +\begin{bnf} +\nontermdef{capture-default}\br + \terminal{\&}\br + \terminal{=} +\end{bnf} + +\begin{bnf} +\nontermdef{capture-list}\br + capture \terminal{...\opt}\br + capture-list \terminal{,} capture \terminal{...\opt} +\end{bnf} + +\begin{bnf} +\nontermdef{capture}\br + simple-capture\br + init-capture +\end{bnf} + +\begin{bnf} +\nontermdef{simple-capture}\br + identifier\br + \terminal{\&} identifier\br + \terminal{this}\br + \terminal{* this} +\end{bnf} + +\begin{bnf} +\nontermdef{init-capture}\br + identifier initializer\br + \terminal{\&} identifier initializer +\end{bnf} + +\pnum +The body of a \grammarterm{lambda-expression} may refer to variables +with automatic storage duration and the \tcode{*this} object (if any) +of enclosing block scopes by capturing those entities, as described +below. + \pnum If a \grammarterm{lambda-capture} includes a \grammarterm{capture-default} that is \tcode{\&}, no identifier in a \grammarterm{simple-capture} of that @@ -1260,23 +1297,6 @@ \end{codeblock} \end{example} -\pnum -The closure type associated with a \grammarterm{lambda-expression} has no -default constructor and a deleted copy assignment operator. It has a -defaulted copy constructor and a defaulted move constructor~(\ref{class.copy}). -\begin{note} These special member functions are implicitly defined as -usual, and might therefore be defined as deleted. \end{note} - -\pnum -The closure type associated with a \grammarterm{lambda-expression} has an -implicitly-declared destructor~(\ref{class.dtor}). - -\pnum -A member of a closure type shall not be -explicitly instantiated~(\ref{temp.explicit}), -explicitly specialized~(\ref{temp.expl.spec}), or -named in a \tcode{friend} declaration~(\ref{class.friend}). - \pnum When the \grammarterm{lambda-expression} is evaluated, the entities that are captured by copy are used to direct-initialize each corresponding non-static data member @@ -4981,7 +5001,7 @@ If the odr-use occurs in an invocation of a function call operator of a closure type, it no longer refers to \tcode{this} or to an enclosing automatic variable -due to the transformation~(\ref{expr.prim.lambda}) +due to the transformation~(\ref{expr.prim.lambda.capture}) of the \grammarterm{id-expression} into an access of the corresponding data member. \begin{example} diff --git a/source/special.tex b/source/special.tex index 7f0b2c3614..d4b425ef2b 100644 --- a/source/special.tex +++ b/source/special.tex @@ -518,7 +518,7 @@ The first context is when a default constructor is called to initialize an element of an array with no corresponding initializer~(\ref{dcl.init}). The second context is when a copy constructor is called to copy an element of -an array while the entire array is copied~(\ref{expr.prim.lambda},~\ref{class.copy}). +an array while the entire array is copied~(\ref{expr.prim.lambda.capture},~\ref{class.copy}). In either case, if the constructor has one or more default arguments, the destruction of every temporary created in a default argument is sequenced before the construction of the next array element, if any. diff --git a/source/templates.tex b/source/templates.tex index 300762b2c1..23227ea937 100644 --- a/source/templates.tex +++ b/source/templates.tex @@ -146,7 +146,7 @@ in a templated entity, \item a member of a templated entity, \item an enumerator for an enumeration that is a templated entity, or -\item the closure type of a \grammarterm{lambda-expression}~(\ref{expr.prim.lambda}) +\item the closure type of a \grammarterm{lambda-expression}~(\ref{expr.prim.lambda.closure}) appearing in the declaration of a templated entity. \end{itemize} @@ -4796,7 +4796,7 @@ the same template parameters and the same access as that of the function template \tcode{f} used at that point, except that the scope in which a closure type is -declared~(\ref{expr.prim.lambda}) -- and therefore its associated namespaces -- +declared~(\ref{expr.prim.lambda.closure}) -- and therefore its associated namespaces -- remain as determined from the context of the definition for the default argument. This analysis is called