Skip to content

Commit 763a3fd

Browse files
jensmaurerzygoloid
authored andcommitted
[expr.prim.lambda] Split specification of lambda expressions into subsections.
Fixes #1155.
1 parent 8139f2f commit 763a3fd

File tree

5 files changed

+135
-117
lines changed

5 files changed

+135
-117
lines changed

source/basic.tex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3673,7 +3673,7 @@
36733673
has all of the following properties:
36743674
\begin{itemize}
36753675
\item it has a trivial destructor,
3676-
\item it is either a closure type~(\ref{expr.prim.lambda}),
3676+
\item it is either a closure type~(\ref{expr.prim.lambda.closure}),
36773677
an aggregate type~(\ref{dcl.init.aggr}), or
36783678
has at least one constexpr constructor or constructor template
36793679
(possibly inherited~(\ref{namespace.udecl}) from a base class)

source/declarations.tex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1545,7 +1545,7 @@
15451545
from an initializer. The \tcode{auto}
15461546
\grammarterm{type-specifier} is also used to
15471547
introduce a function type having a \grammarterm{trailing-return-type} or to
1548-
signify that a lambda is a generic lambda (\ref{expr.prim.lambda}).
1548+
signify that a lambda is a generic lambda (\ref{expr.prim.lambda.closure}).
15491549
The \tcode{auto} \grammarterm{type-specifier} is also used to introduce a
15501550
structured binding declaration (\ref{dcl.struct.bind}).
15511551

@@ -1567,7 +1567,7 @@
15671567
\grammarterm{decl-specifier}{s} in the \grammarterm{decl-specifier-seq} of a
15681568
\grammarterm{parameter-declaration} of a \grammarterm{lambda-expression}, the
15691569
\indextext{generic lambda!definition of}%
1570-
lambda is a \term{generic lambda}~(\ref{expr.prim.lambda}). \begin{example}
1570+
lambda is a \term{generic lambda}~(\ref{expr.prim.lambda.closure}). \begin{example}
15711571
\begin{codeblock}
15721572
auto glambda = [](int i, auto a) { return i; }; // OK: a generic lambda
15731573
\end{codeblock}

source/expressions.tex

Lines changed: 129 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -602,45 +602,6 @@
602602
\terminal{[} lambda-capture\opt{} \terminal{]}
603603
\end{bnf}
604604

605-
\begin{bnf}
606-
\nontermdef{lambda-capture}\br
607-
capture-default\br
608-
capture-list\br
609-
capture-default \terminal{,} capture-list
610-
\end{bnf}
611-
612-
\begin{bnf}
613-
\nontermdef{capture-default}\br
614-
\terminal{\&}\br
615-
\terminal{=}
616-
\end{bnf}
617-
618-
\begin{bnf}
619-
\nontermdef{capture-list}\br
620-
capture \terminal{...\opt}\br
621-
capture-list \terminal{,} capture \terminal{...\opt}
622-
\end{bnf}
623-
624-
\begin{bnf}
625-
\nontermdef{capture}\br
626-
simple-capture\br
627-
init-capture
628-
\end{bnf}
629-
630-
\begin{bnf}
631-
\nontermdef{simple-capture}\br
632-
identifier\br
633-
\terminal{\&} identifier\br
634-
\terminal{this}\br
635-
\terminal{* this}
636-
\end{bnf}
637-
638-
\begin{bnf}
639-
\nontermdef{init-capture}\br
640-
identifier initializer\br
641-
\terminal{\&} identifier initializer
642-
\end{bnf}
643-
644605
\begin{bnf}
645606
\nontermdef{lambda-declarator}\br
646607
\terminal{(} parameter-declaration-clause \terminal{)} decl-specifier-seq\opt\br
@@ -659,37 +620,6 @@
659620
\end{codeblock}
660621
\end{example}
661622

662-
\pnum
663-
In the \grammarterm{decl-specifier-seq} of the \grammarterm{lambda-declarator},
664-
each \grammarterm{decl-specifier}
665-
shall either be \tcode{mutable} or \tcode{constexpr}.
666-
\begin{example}
667-
\begin{codeblock}
668-
auto monoid = [](auto v) { return [=] { return v; }; };
669-
auto add = [](auto m1) constexpr {
670-
auto ret = m1();
671-
return [=](auto m2) mutable {
672-
auto m1val = m1();
673-
auto plus = [=](auto m2val) mutable constexpr
674-
{ return m1val += m2val; };
675-
ret = plus(m2());
676-
return monoid(ret);
677-
};
678-
};
679-
constexpr auto zero = monoid(0);
680-
constexpr auto one = monoid(1);
681-
static_assert(add(one)(zero)() == one()); // OK
682-
683-
// Since \tcode{two} below is not declared \tcode{constexpr}, an evaluation of its \tcode{constexpr} member function call operator
684-
// cannot perform an lvalue-to-rvalue conversion on one of its subobjects (that represents its capture)
685-
// in a constant expression.
686-
auto two = monoid(2);
687-
assert(two() == 2); // OK, not a constant expression.
688-
static_assert(add(one)(one)() == two()); // ill-formed: \tcode{two()} is not a constant expression
689-
static_assert(add(one)(one)() == monoid(2)()); // OK
690-
\end{codeblock}
691-
\end{example}
692-
693623
\pnum
694624
A \grammarterm{lambda-expression} is a prvalue
695625
whose result object is called the \defn{closure object}. A
@@ -706,17 +636,38 @@
706636
object~(\ref{function.objects}).\end{note}
707637

708638
\pnum
709-
The type of the \grammarterm{lambda-expression} (which is also the type of the
710-
closure object) is a unique, unnamed non-union class type
711-
--- called the \defn{closure type} ---
639+
If a \grammarterm{lambda-expression} does not include a
640+
\grammarterm{lambda-declarator}, it is as if the \grammarterm{lambda-declarator} were
641+
\tcode{()}.
642+
The lambda return type is \tcode{auto}, which is replaced by the
643+
type specified by the
644+
\grammarterm{trailing-return-type} if provided and/or deduced from
645+
\tcode{return} statements as described in~\ref{dcl.spec.auto}.
646+
\begin{example}
647+
\begin{codeblock}
648+
auto x1 = [](int i){ return i; }; // OK: return type is \tcode{int}
649+
auto x2 = []{ return { 1, 2 }; }; // error: deducing return type from \grammarterm{braced-init-list}
650+
int j;
651+
auto x3 = []()->auto&& { return j; }; // OK: return type is \tcode{int\&}
652+
\end{codeblock}
653+
\end{example}
654+
655+
\rSec3[expr.prim.lambda.closure]{Closure types}%
656+
657+
\pnum
658+
The type of a \grammarterm{lambda-expression} (which is also the type of the
659+
closure object) is a unique, unnamed non-union class type,
660+
called the \defn{closure type},
712661
whose properties are described below.
713-
This class type is not an aggregate type~(\ref{dcl.init.aggr}).
662+
663+
\pnum
714664
The closure type is declared in the smallest block
715665
scope, class scope, or namespace scope that contains the corresponding
716666
\grammarterm{lambda-expression}. \begin{note} This determines the set of namespaces and
717667
classes associated with the closure type~(\ref{basic.lookup.argdep}). The parameter
718668
types of a \grammarterm{lambda-declarator} do not affect these associated namespaces and
719-
classes. \end{note} An implementation may define the closure type differently from what
669+
classes. \end{note} The closure type is not an aggregate type~(\ref{dcl.init.aggr}).
670+
An implementation may define the closure type differently from what
720671
is described below provided this does not alter the observable behavior of the program
721672
other than by changing:
722673

@@ -734,23 +685,6 @@
734685
An implementation shall not add members of rvalue reference type to the closure
735686
type.
736687

737-
\pnum
738-
If a \grammarterm{lambda-expression} does not include a
739-
\grammarterm{lambda-declarator}, it is as if the \grammarterm{lambda-declarator} were
740-
\tcode{()}.
741-
The lambda return type is \tcode{auto}, which is replaced by the
742-
type specified by the
743-
\grammarterm{trailing-return-type} if provided and/or deduced from
744-
\tcode{return} statements as described in~\ref{dcl.spec.auto}.
745-
\begin{example}
746-
\begin{codeblock}
747-
auto x1 = [](int i){ return i; }; // OK: return type is \tcode{int}
748-
auto x2 = []{ return { 1, 2 }; }; // error: deducing return type from \grammarterm{braced-init-list}
749-
int j;
750-
auto x3 = []()->auto&& { return j; }; // OK: return type is \tcode{int\&}
751-
\end{codeblock}
752-
\end{example}
753-
754688
\pnum
755689
The closure type for a non-generic \grammarterm{lambda-expression} has a public
756690
inline function call operator~(\ref{over.call}) whose parameters and return type
@@ -791,7 +725,12 @@
791725
q(); // OK: outputs \tcode{1a3.14}
792726
\end{codeblock}
793727
\end{example}
794-
This function call operator or operator template is declared
728+
729+
\pnum
730+
In the \grammarterm{decl-specifier-seq} of the \grammarterm{lambda-declarator},
731+
each \grammarterm{decl-specifier}
732+
shall either be \tcode{mutable} or \tcode{constexpr}.
733+
The function call operator or operator template is declared
795734
\tcode{const}~(\ref{class.mfct.non-static}) if and only if the
796735
\grammarterm{lambda-expression}'s \grammarterm{parameter-declaration-clause} is not
797736
followed by \tcode{mutable}. It is neither virtual nor declared \tcode{volatile}. Any
@@ -820,6 +759,34 @@
820759
\end{codeblock}
821760
\end{example}
822761

762+
\pnum
763+
\begin{example}
764+
\begin{codeblock}
765+
auto monoid = [](auto v) { return [=] { return v; }; };
766+
auto add = [](auto m1) constexpr {
767+
auto ret = m1();
768+
return [=](auto m2) mutable {
769+
auto m1val = m1();
770+
auto plus = [=](auto m2val) mutable constexpr
771+
{ return m1val += m2val; };
772+
ret = plus(m2());
773+
return monoid(ret);
774+
};
775+
};
776+
constexpr auto zero = monoid(0);
777+
constexpr auto one = monoid(1);
778+
static_assert(add(one)(zero)() == one()); // OK
779+
780+
// Since \tcode{two} below is not declared \tcode{constexpr}, an evaluation of its \tcode{constexpr} member function call operator
781+
// cannot perform an lvalue-to-rvalue conversion on one of its subobjects (that represents its capture)
782+
// in a constant expression.
783+
auto two = monoid(2);
784+
assert(two() == 2); // OK, not a constant expression.
785+
static_assert(add(one)(one)() == two()); // ill-formed: \tcode{two()} is not a constant expression
786+
static_assert(add(one)(one)() == monoid(2)()); // OK
787+
\end{codeblock}
788+
\end{example}
789+
823790
\pnum
824791
The closure type for a non-generic \grammarterm{lambda-expression} with no
825792
\grammarterm{lambda-capture}
@@ -842,6 +809,8 @@
842809
the pointer to function shall behave as if it were a
843810
\grammarterm{decltype-specifier} denoting the return type of the corresponding
844811
function call operator template specialization.
812+
813+
\pnum
845814
\begin{note}
846815
If the generic lambda has no \grammarterm{trailing-return-type} or
847816
the \grammarterm{trailing-return-type} contains a placeholder type, return type
@@ -892,6 +861,7 @@
892861
\end{codeblock}
893862
\end{example}
894863

864+
\pnum
895865
The value returned by any given specialization of this conversion function
896866
template is the address of a function \tcode{F} that, when invoked, has the same
897867
effect as invoking the generic lambda's corresponding function call operator
@@ -911,6 +881,7 @@
911881
\end{codeblock}
912882
\end{example}
913883

884+
\pnum
914885
The conversion function or conversion function template is public,
915886
constexpr, non-virtual, non-explicit, const, and has a non-throwing exception
916887
specification~(\ref{except.spec}).
@@ -953,6 +924,70 @@
953924
the \grammarterm{compound-statement} of the \grammarterm{lambda-expression},
954925
with semantics as described in~\ref{dcl.fct.def.general}.
955926

927+
\pnum
928+
The closure type associated with a \grammarterm{lambda-expression} has no
929+
default constructor and a deleted copy assignment operator. It has a
930+
defaulted copy constructor and a defaulted move constructor~(\ref{class.copy}).
931+
\begin{note} These special member functions are implicitly defined as
932+
usual, and might therefore be defined as deleted. \end{note}
933+
934+
\pnum
935+
The closure type associated with a \grammarterm{lambda-expression} has an
936+
implicitly-declared destructor~(\ref{class.dtor}).
937+
938+
\pnum
939+
A member of a closure type shall not be
940+
explicitly instantiated~(\ref{temp.explicit}),
941+
explicitly specialized~(\ref{temp.expl.spec}), or
942+
named in a \tcode{friend} declaration~(\ref{class.friend}).
943+
944+
\rSec3[expr.prim.lambda.capture]{Captures}%
945+
946+
\begin{bnf}
947+
\nontermdef{lambda-capture}\br
948+
capture-default\br
949+
capture-list\br
950+
capture-default \terminal{,} capture-list
951+
\end{bnf}
952+
953+
\begin{bnf}
954+
\nontermdef{capture-default}\br
955+
\terminal{\&}\br
956+
\terminal{=}
957+
\end{bnf}
958+
959+
\begin{bnf}
960+
\nontermdef{capture-list}\br
961+
capture \terminal{...\opt}\br
962+
capture-list \terminal{,} capture \terminal{...\opt}
963+
\end{bnf}
964+
965+
\begin{bnf}
966+
\nontermdef{capture}\br
967+
simple-capture\br
968+
init-capture
969+
\end{bnf}
970+
971+
\begin{bnf}
972+
\nontermdef{simple-capture}\br
973+
identifier\br
974+
\terminal{\&} identifier\br
975+
\terminal{this}\br
976+
\terminal{* this}
977+
\end{bnf}
978+
979+
\begin{bnf}
980+
\nontermdef{init-capture}\br
981+
identifier initializer\br
982+
\terminal{\&} identifier initializer
983+
\end{bnf}
984+
985+
\pnum
986+
The body of a \grammarterm{lambda-expression} may refer to variables
987+
with automatic storage duration and the \tcode{*this} object (if any)
988+
of enclosing block scopes by capturing those entities, as described
989+
below.
990+
956991
\pnum
957992
If a \grammarterm{lambda-capture} includes a \grammarterm{capture-default} that
958993
is \tcode{\&}, no identifier in a \grammarterm{simple-capture} of that
@@ -1292,23 +1327,6 @@
12921327
\end{codeblock}
12931328
\end{example}
12941329

1295-
\pnum
1296-
The closure type associated with a \grammarterm{lambda-expression} has no
1297-
default constructor and a deleted copy assignment operator. It has a
1298-
defaulted copy constructor and a defaulted move constructor~(\ref{class.copy}).
1299-
\begin{note} These special member functions are implicitly defined as
1300-
usual, and might therefore be defined as deleted. \end{note}
1301-
1302-
\pnum
1303-
The closure type associated with a \grammarterm{lambda-expression} has an
1304-
implicitly-declared destructor~(\ref{class.dtor}).
1305-
1306-
\pnum
1307-
A member of a closure type shall not be
1308-
explicitly instantiated~(\ref{temp.explicit}),
1309-
explicitly specialized~(\ref{temp.expl.spec}), or
1310-
named in a \tcode{friend} declaration~(\ref{class.friend}).
1311-
13121330
\pnum
13131331
When the \grammarterm{lambda-expression} is evaluated, the entities that are
13141332
captured by copy are used to direct-initialize each corresponding non-static data member
@@ -5030,7 +5048,7 @@
50305048
If the odr-use occurs in an invocation
50315049
of a function call operator of a closure type,
50325050
it no longer refers to \tcode{this} or to an enclosing automatic variable
5033-
due to the transformation~(\ref{expr.prim.lambda})
5051+
due to the transformation~(\ref{expr.prim.lambda.capture})
50345052
of the \grammarterm{id-expression} into
50355053
an access of the corresponding data member.
50365054
\begin{example}

source/special.tex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -521,7 +521,7 @@
521521
The first context is when a default constructor is called to initialize
522522
an element of an array with no corresponding initializer~(\ref{dcl.init}).
523523
The second context is when a copy constructor is called to copy an element of
524-
an array while the entire array is copied~(\ref{expr.prim.lambda},~\ref{class.copy}).
524+
an array while the entire array is copied~(\ref{expr.prim.lambda.capture},~\ref{class.copy}).
525525
In either case, if the constructor has one or more default arguments,
526526
the destruction of every temporary created in a default argument is
527527
sequenced before the construction of the next array element, if any.

source/templates.tex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@
146146
in a templated entity,
147147
\item a member of a templated entity,
148148
\item an enumerator for an enumeration that is a templated entity, or
149-
\item the closure type of a \grammarterm{lambda-expression}~(\ref{expr.prim.lambda})
149+
\item the closure type of a \grammarterm{lambda-expression}~(\ref{expr.prim.lambda.closure})
150150
appearing in the declaration of a templated entity.
151151
\end{itemize}
152152

@@ -4806,7 +4806,7 @@
48064806
the same template parameters and the same access as that of the function template
48074807
\tcode{f}
48084808
used at that point, except that the scope in which a closure type is
4809-
declared~(\ref{expr.prim.lambda}) -- and therefore its associated namespaces --
4809+
declared~(\ref{expr.prim.lambda.closure}) -- and therefore its associated namespaces --
48104810
remain as determined from the context of the definition for the default
48114811
argument.
48124812
This analysis is called

0 commit comments

Comments
 (0)