From Jason Turner

[expr.prim.lambda.closure]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmplxu48114/{from.md → to.md} +104 -69
tmp/tmplxu48114/{from.md → to.md} RENAMED
@@ -6,44 +6,40 @@ type*, whose properties are described below.
6
 
7
  The closure type is declared in the smallest block scope, class scope,
8
  or namespace scope that contains the corresponding *lambda-expression*.
9
 
10
  [*Note 1*: This determines the set of namespaces and classes associated
11
- with the closure type ([[basic.lookup.argdep]]). The parameter types of
12
- a *lambda-declarator* do not affect these associated namespaces and
13
  classes. — *end note*]
14
 
15
- The closure type is not an aggregate type ([[dcl.init.aggr]]). An
16
  implementation may define the closure type differently from what is
17
  described below provided this does not alter the observable behavior of
18
  the program other than by changing:
19
 
20
  - the size and/or alignment of the closure type,
21
- - whether the closure type is trivially copyable (Clause  [[class]]),
22
- - whether the closure type is a standard-layout class (Clause 
23
- [[class]]), or
24
- - whether the closure type is a POD class (Clause  [[class]]).
25
 
26
  An implementation shall not add members of rvalue reference type to the
27
  closure type.
28
 
29
- The closure type for a non-generic *lambda-expression* has a public
30
- inline function call operator ([[over.call]]) whose parameters and
 
31
  return type are described by the *lambda-expression*’s
32
- *parameter-declaration-clause* and *trailing-return-type* respectively.
33
- For a generic lambda, the closure type has a public inline function call
34
- operator member template ([[temp.mem]]) whose *template-parameter-list*
35
- consists of one invented type *template-parameter* for each occurrence
36
- of `auto` in the lambda’s *parameter-declaration-clause*, in order of
37
- appearance. The invented type *template-parameter* is a parameter pack
38
- if the corresponding *parameter-declaration* declares a function
39
- parameter pack ([[dcl.fct]]). The return type and function parameters
40
- of the function call operator template are derived from the
41
- *lambda-expression*'s *trailing-return-type* and
42
- *parameter-declaration-clause* by replacing each occurrence of `auto` in
43
- the *decl-specifier*s of the *parameter-declaration-clause* with the
44
- name of the corresponding invented *template-parameter*.
45
 
46
  [*Example 1*:
47
 
48
  ``` cpp
49
  auto glambda = [](auto a, auto&& b) { return a < b; };
@@ -74,14 +70,17 @@ specified on a *lambda-expression* applies to the corresponding function
74
  call operator or operator template. An *attribute-specifier-seq* in a
75
  *lambda-declarator* appertains to the type of the corresponding function
76
  call operator or operator template. The function call operator or any
77
  given operator template specialization is a constexpr function if either
78
  the corresponding *lambda-expression*'s *parameter-declaration-clause*
79
- is followed by `constexpr`, or it satisfies the requirements for a
80
- constexpr function ([[dcl.constexpr]]).
 
 
 
81
 
82
- [*Note 2*: Names referenced in the *lambda-declarator* are looked up in
83
  the context in which the *lambda-expression* appears. — *end note*]
84
 
85
  [*Example 2*:
86
 
87
  ``` cpp
@@ -90,11 +89,11 @@ static_assert(ID(3) == 3); // OK
90
 
91
  struct NonLiteral {
92
  NonLiteral(int n) : n(n) { }
93
  int n;
94
  };
95
- static_assert(ID(NonLiteral{3}).n == 3); // ill-formed
96
  ```
97
 
98
  — *end example*]
99
 
100
  [*Example 3*:
@@ -118,35 +117,65 @@ static_assert(add(one)(zero)() == one()); // OK
118
  // Since two below is not declared constexpr, an evaluation of its constexpr member function call operator
119
  // cannot perform an lvalue-to-rvalue conversion on one of its subobjects (that represents its capture)
120
  // in a constant expression.
121
  auto two = monoid(2);
122
  assert(two() == 2); // OK, not a constant expression.
123
- static_assert(add(one)(one)() == two()); // ill-formed: two() is not a constant expression
124
  static_assert(add(one)(one)() == monoid(2)()); // OK
125
  ```
126
 
127
  — *end example*]
128
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
  The closure type for a non-generic *lambda-expression* with no
130
- *lambda-capture* has a conversion function to pointer to function with
131
- C++language linkage ([[dcl.link]]) having the same parameter and return
132
- types as the closure type’s function call operator. The conversion is to
133
- “pointer to `noexcept` function if the function call operator has a
134
- non-throwing exception specification. The value returned by this
135
- conversion function is the address of a function `F` that, when invoked,
136
- has the same effect as invoking the closure type’s function call
137
- operator. `F` is a constexpr function if the function call operator is a
138
- constexpr function. For a generic lambda with no *lambda-capture*, the
139
- closure type has a conversion function template to pointer to function.
140
- The conversion function template has the same invented
141
- *template-parameter-list*, and the pointer to function has the same
142
- parameter types, as the function call operator template. The return type
143
- of the pointer to function shall behave as if it were a
144
- *decltype-specifier* denoting the return type of the corresponding
145
- function call operator template specialization.
146
 
147
- [*Note 3*:
 
 
 
 
 
 
 
 
148
 
149
  If the generic lambda has no *trailing-return-type* or the
150
  *trailing-return-type* contains a placeholder type, return type
151
  deduction of the corresponding function call operator template
152
  specialization has to be done. The corresponding specialization is that
@@ -178,11 +207,11 @@ struct Closure {
178
  };
179
  ```
180
 
181
  — *end note*]
182
 
183
- [*Example 4*:
184
 
185
  ``` cpp
186
  void f1(int (*)(int)) { }
187
  void f2(char (*)(int)) { }
188
 
@@ -203,19 +232,22 @@ int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK
203
  — *end example*]
204
 
205
  The value returned by any given specialization of this conversion
206
  function template is the address of a function `F` that, when invoked,
207
  has the same effect as invoking the generic lambda’s corresponding
208
- function call operator template specialization. `F` is a constexpr
209
- function if the corresponding specialization is a constexpr function.
 
 
 
210
 
211
- [*Note 4*: This will result in the implicit instantiation of the
212
  generic lambda’s body. The instantiated generic lambda’s return type and
213
- parameter types shall match the return type and parameter types of the
214
- pointer to function. — *end note*]
215
 
216
- [*Example 5*:
217
 
218
  ``` cpp
219
  auto GL = [](auto a) { std::cout << a; return a; };
220
  int (*GL_int)(int) = GL; // OK: through conversion function template
221
  GL_int(3); // OK: same as GL(3)
@@ -223,37 +255,36 @@ GL_int(3); // OK: same as GL(3)
223
 
224
  — *end example*]
225
 
226
  The conversion function or conversion function template is public,
227
  constexpr, non-virtual, non-explicit, const, and has a non-throwing
228
- exception specification ([[except.spec]]).
229
 
230
- [*Example 6*:
231
 
232
  ``` cpp
233
  auto Fwd = [](int (*fp)(int), auto a) { return fp(a); };
234
  auto C = [](auto a) { return a; };
235
 
236
  static_assert(Fwd(C,3) == 3); // OK
237
 
238
  // No specialization of the function call operator template can be constexpr (due to the local static).
239
  auto NC = [](auto a) { static int s; return a; };
240
- static_assert(Fwd(NC,3) == 3); // ill-formed
241
  ```
242
 
243
  — *end example*]
244
 
245
  The *lambda-expression*’s *compound-statement* yields the
246
- *function-body* ([[dcl.fct.def]]) of the function call operator, but
247
- for purposes of name lookup ([[basic.lookup]]), determining the type
248
- and value of `this` ([[class.this]]) and transforming *id-expression*s
249
- referring to non-static class members into class member access
250
- expressions using `(*this)` ([[class.mfct.non-static]]), the
251
- *compound-statement* is considered in the context of the
252
- *lambda-expression*.
253
 
254
- [*Example 7*:
255
 
256
  ``` cpp
257
  struct S1 {
258
  int x, y;
259
  int operator()(int);
@@ -271,18 +302,22 @@ struct S1 {
271
  Further, a variable `__func__` is implicitly defined at the beginning of
272
  the *compound-statement* of the *lambda-expression*, with semantics as
273
  described in  [[dcl.fct.def.general]].
274
 
275
  The closure type associated with a *lambda-expression* has no default
276
- constructor and a deleted copy assignment operator. It has a defaulted
277
- copy constructor and a defaulted move constructor ([[class.copy]]).
 
 
 
 
278
 
279
- [*Note 5*: These special member functions are implicitly defined as
280
  usual, and might therefore be defined as deleted. — *end note*]
281
 
282
  The closure type associated with a *lambda-expression* has an
283
- implicitly-declared destructor ([[class.dtor]]).
284
 
285
- A member of a closure type shall not be explicitly instantiated (
286
- [[temp.explicit]]), explicitly specialized ([[temp.expl.spec]]), or
287
- named in a `friend` declaration ([[class.friend]]).
288
 
 
6
 
7
  The closure type is declared in the smallest block scope, class scope,
8
  or namespace scope that contains the corresponding *lambda-expression*.
9
 
10
  [*Note 1*: This determines the set of namespaces and classes associated
11
+ with the closure type [[basic.lookup.argdep]]. The parameter types of a
12
+ *lambda-declarator* do not affect these associated namespaces and
13
  classes. — *end note*]
14
 
15
+ The closure type is not an aggregate type [[dcl.init.aggr]]. An
16
  implementation may define the closure type differently from what is
17
  described below provided this does not alter the observable behavior of
18
  the program other than by changing:
19
 
20
  - the size and/or alignment of the closure type,
21
+ - whether the closure type is trivially copyable [[class.prop]], or
22
+ - whether the closure type is a standard-layout class [[class.prop]].
 
 
23
 
24
  An implementation shall not add members of rvalue reference type to the
25
  closure type.
26
 
27
+ The closure type for a *lambda-expression* has a public inline function
28
+ call operator (for a non-generic lambda) or function call operator
29
+ template (for a generic lambda) [[over.call]] whose parameters and
30
  return type are described by the *lambda-expression*’s
31
+ *parameter-declaration-clause* and *trailing-return-type* respectively,
32
+ and whose *template-parameter-list* consists of the specified
33
+ *template-parameter-list*, if any. The *requires-clause* of the function
34
+ call operator template is the *requires-clause* immediately following
35
+ `<` *template-parameter-list* `>`, if any. The trailing
36
+ *requires-clause* of the function call operator or operator template is
37
+ the *requires-clause* of the *lambda-declarator*, if any.
38
+
39
+ [*Note 2*: The function call operator template for a generic lambda
40
+ might be an abbreviated function template [[dcl.fct]]. — *end note*]
 
 
 
41
 
42
  [*Example 1*:
43
 
44
  ``` cpp
45
  auto glambda = [](auto a, auto&& b) { return a < b; };
 
70
  call operator or operator template. An *attribute-specifier-seq* in a
71
  *lambda-declarator* appertains to the type of the corresponding function
72
  call operator or operator template. The function call operator or any
73
  given operator template specialization is a constexpr function if either
74
  the corresponding *lambda-expression*'s *parameter-declaration-clause*
75
+ is followed by `constexpr` or `consteval`, or it satisfies the
76
+ requirements for a constexpr function [[dcl.constexpr]]. It is an
77
+ immediate function [[dcl.constexpr]] if the corresponding
78
+ *lambda-expression*'s *parameter-declaration-clause* is followed by
79
+ `consteval`.
80
 
81
+ [*Note 3*: Names referenced in the *lambda-declarator* are looked up in
82
  the context in which the *lambda-expression* appears. — *end note*]
83
 
84
  [*Example 2*:
85
 
86
  ``` cpp
 
89
 
90
  struct NonLiteral {
91
  NonLiteral(int n) : n(n) { }
92
  int n;
93
  };
94
+ static_assert(ID(NonLiteral{3}).n == 3); // error
95
  ```
96
 
97
  — *end example*]
98
 
99
  [*Example 3*:
 
117
  // Since two below is not declared constexpr, an evaluation of its constexpr member function call operator
118
  // cannot perform an lvalue-to-rvalue conversion on one of its subobjects (that represents its capture)
119
  // in a constant expression.
120
  auto two = monoid(2);
121
  assert(two() == 2); // OK, not a constant expression.
122
+ static_assert(add(one)(one)() == two()); // error: two() is not a constant expression
123
  static_assert(add(one)(one)() == monoid(2)()); // OK
124
  ```
125
 
126
  — *end example*]
127
 
128
+ [*Note 4*:
129
+
130
+ The function call operator or operator template may be constrained
131
+ [[temp.constr.decl]] by a *type-constraint* [[temp.param]], a
132
+ *requires-clause* [[temp.pre]], or a trailing *requires-clause*
133
+ [[dcl.decl]].
134
+
135
+ [*Example 4*:
136
+
137
+ ``` cpp
138
+ template <typename T> concept C1 = ...;
139
+ template <std::size_t N> concept C2 = ...;
140
+ template <typename A, typename B> concept C3 = ...;
141
+
142
+ auto f = []<typename T1, C1 T2> requires C2<sizeof(T1) + sizeof(T2)>
143
+ (T1 a1, T1 b1, T2 a2, auto a3, auto a4) requires C3<decltype(a4), T2> {
144
+ // T2 is constrained by a type-constraint.
145
+ // T1 and T2 are constrained by a requires-clause, and
146
+ // T2 and the type of a4 are constrained by a trailing requires-clause.
147
+ };
148
+ ```
149
+
150
+ — *end example*]
151
+
152
+ — *end note*]
153
+
154
  The closure type for a non-generic *lambda-expression* with no
155
+ *lambda-capture* whose constraints (if any) are satisfied has a
156
+ conversion function to pointer to function with C++ language linkage
157
+ [[dcl.link]] having the same parameter and return types as the closure
158
+ type’s function call operator. The conversion is to “pointer to
159
+ `noexcept` function” if the function call operator has a non-throwing
160
+ exception specification. The value returned by this conversion function
161
+ is the address of a function `F` that, when invoked, has the same effect
162
+ as invoking the closure type’s function call operator on a
163
+ default-constructed instance of the closure type. `F` is a constexpr
164
+ function if the function call operator is a constexpr function and is an
165
+ immediate function if the function call operator is an immediate
166
+ function.
 
 
 
 
167
 
168
+ For a generic lambda with no *lambda-capture*, the closure type has a
169
+ conversion function template to pointer to function. The conversion
170
+ function template has the same invented template parameter list, and the
171
+ pointer to function has the same parameter types, as the function call
172
+ operator template. The return type of the pointer to function shall
173
+ behave as if it were a *decltype-specifier* denoting the return type of
174
+ the corresponding function call operator template specialization.
175
+
176
+ [*Note 5*:
177
 
178
  If the generic lambda has no *trailing-return-type* or the
179
  *trailing-return-type* contains a placeholder type, return type
180
  deduction of the corresponding function call operator template
181
  specialization has to be done. The corresponding specialization is that
 
207
  };
208
  ```
209
 
210
  — *end note*]
211
 
212
+ [*Example 5*:
213
 
214
  ``` cpp
215
  void f1(int (*)(int)) { }
216
  void f2(char (*)(int)) { }
217
 
 
232
  — *end example*]
233
 
234
  The value returned by any given specialization of this conversion
235
  function template is the address of a function `F` that, when invoked,
236
  has the same effect as invoking the generic lambda’s corresponding
237
+ function call operator template specialization on a default-constructed
238
+ instance of the closure type. `F` is a constexpr function if the
239
+ corresponding specialization is a constexpr function and `F` is an
240
+ immediate function if the function call operator template specialization
241
+ is an immediate function.
242
 
243
+ [*Note 6*: This will result in the implicit instantiation of the
244
  generic lambda’s body. The instantiated generic lambda’s return type and
245
+ parameter types are required to match the return type and parameter
246
+ types of the pointer to function. — *end note*]
247
 
248
+ [*Example 6*:
249
 
250
  ``` cpp
251
  auto GL = [](auto a) { std::cout << a; return a; };
252
  int (*GL_int)(int) = GL; // OK: through conversion function template
253
  GL_int(3); // OK: same as GL(3)
 
255
 
256
  — *end example*]
257
 
258
  The conversion function or conversion function template is public,
259
  constexpr, non-virtual, non-explicit, const, and has a non-throwing
260
+ exception specification [[except.spec]].
261
 
262
+ [*Example 7*:
263
 
264
  ``` cpp
265
  auto Fwd = [](int (*fp)(int), auto a) { return fp(a); };
266
  auto C = [](auto a) { return a; };
267
 
268
  static_assert(Fwd(C,3) == 3); // OK
269
 
270
  // No specialization of the function call operator template can be constexpr (due to the local static).
271
  auto NC = [](auto a) { static int s; return a; };
272
+ static_assert(Fwd(NC,3) == 3); // error
273
  ```
274
 
275
  — *end example*]
276
 
277
  The *lambda-expression*’s *compound-statement* yields the
278
+ *function-body* [[dcl.fct.def]] of the function call operator, but for
279
+ purposes of name lookup [[basic.lookup]], determining the type and value
280
+ of `this` [[class.this]] and transforming *id-expression*s referring to
281
+ non-static class members into class member access expressions using
282
+ `(*this)` ([[class.mfct.non-static]]), the *compound-statement* is
283
+ considered in the context of the *lambda-expression*.
 
284
 
285
+ [*Example 8*:
286
 
287
  ``` cpp
288
  struct S1 {
289
  int x, y;
290
  int operator()(int);
 
302
  Further, a variable `__func__` is implicitly defined at the beginning of
303
  the *compound-statement* of the *lambda-expression*, with semantics as
304
  described in  [[dcl.fct.def.general]].
305
 
306
  The closure type associated with a *lambda-expression* has no default
307
+ constructor if the *lambda-expression* has a *lambda-capture* and a
308
+ defaulted default constructor otherwise. It has a defaulted copy
309
+ constructor and a defaulted move constructor [[class.copy.ctor]]. It has
310
+ a deleted copy assignment operator if the *lambda-expression* has a
311
+ *lambda-capture* and defaulted copy and move assignment operators
312
+ otherwise [[class.copy.assign]].
313
 
314
+ [*Note 7*: These special member functions are implicitly defined as
315
  usual, and might therefore be defined as deleted. — *end note*]
316
 
317
  The closure type associated with a *lambda-expression* has an
318
+ implicitly-declared destructor [[class.dtor]].
319
 
320
+ A member of a closure type shall not be explicitly instantiated
321
+ [[temp.explicit]], explicitly specialized [[temp.expl.spec]], or named
322
+ in a friend declaration [[class.friend]].
323