From Jason Turner

[expr.prim.lambda.closure]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmphm8bxc4d/{from.md → to.md} +89 -53
tmp/tmphm8bxc4d/{from.md → to.md} RENAMED
@@ -34,56 +34,90 @@ and whose *template-parameter-list* consists of the specified
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; };
46
  bool b = glambda(3, 3.14); // OK
47
 
48
  auto vglambda = [](auto printer) {
49
- return [=](auto&& ... ts) { // OK: ts is a function parameter pack
50
  printer(std::forward<decltype(ts)>(ts)...);
51
 
52
  return [=]() {
53
  printer(ts ...);
54
  };
55
  };
56
  };
57
  auto p = vglambda( [](auto v1, auto v2, auto v3)
58
  { std::cout << v1 << v2 << v3; } );
59
- auto q = p(1, 'a', 3.14); // OK: outputs 1a3.14
60
- q(); // OK: outputs 1a3.14
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  ```
62
 
63
  — *end example*]
64
 
65
- The function call operator or operator template is declared `const` (
66
- [[class.mfct.non-static]]) if and only if the *lambda-expression*’s
67
- *parameter-declaration-clause* is not followed by `mutable`. It is
 
 
 
 
 
68
  neither virtual nor declared `volatile`. Any *noexcept-specifier*
69
  specified on a *lambda-expression* applies to the corresponding function
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
87
  auto ID = [](auto a) { return a; };
88
  static_assert(ID(3) == 3); // OK
89
 
@@ -94,11 +128,11 @@ struct NonLiteral {
94
  static_assert(ID(NonLiteral{3}).n == 3); // error
95
  ```
96
 
97
  — *end example*]
98
 
99
- [*Example 3*:
100
 
101
  ``` cpp
102
  auto monoid = [](auto v) { return [=] { return v; }; };
103
  auto add = [](auto m1) constexpr {
104
  auto ret = m1();
@@ -123,18 +157,18 @@ static_assert(add(one)(one)() == two()); // error: two() is not a constan
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 = ...;
@@ -155,27 +189,29 @@ 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,11 +243,11 @@ struct Closure {
207
  };
208
  ```
209
 
210
  — *end note*]
211
 
212
- [*Example 5*:
213
 
214
  ``` cpp
215
  void f1(int (*)(int)) { }
216
  void f2(char (*)(int)) { }
217
 
@@ -223,45 +259,49 @@ void h(char (*)(int)) { } // #4
223
 
224
  auto glambda = [](auto a) { return a; };
225
  f1(glambda); // OK
226
  f2(glambda); // error: ID is not convertible
227
  g(glambda); // error: ambiguous
228
- h(glambda); // OK: calls #3 since it is convertible from ID
229
  int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK
230
  ```
231
 
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)
254
  ```
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
 
@@ -273,18 +313,14 @@ 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);
@@ -309,12 +345,12 @@ 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
 
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 can
40
+ 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; };
46
  bool b = glambda(3, 3.14); // OK
47
 
48
  auto vglambda = [](auto printer) {
49
+ return [=](auto&& ... ts) { // OK, ts is a function parameter pack
50
  printer(std::forward<decltype(ts)>(ts)...);
51
 
52
  return [=]() {
53
  printer(ts ...);
54
  };
55
  };
56
  };
57
  auto p = vglambda( [](auto v1, auto v2, auto v3)
58
  { std::cout << v1 << v2 << v3; } );
59
+ auto q = p(1, 'a', 3.14); // OK, outputs 1a3.14
60
+ q(); // OK, outputs 1a3.14
61
+
62
+ auto fact = [](this auto self, int n) -> int { // OK, explicit object parameter
63
+ return (n <= 1) ? 1 : n * self(n-1);
64
+ };
65
+ std::cout << fact(5); // OK, outputs 120
66
+ ```
67
+
68
+ — *end example*]
69
+
70
+ Given a lambda with a *lambda-capture*, the type of the explicit object
71
+ parameter, if any, of the lambda’s function call operator (possibly
72
+ instantiated from a function call operator template) shall be either:
73
+
74
+ - the closure type,
75
+ - a class type derived from the closure type, or
76
+ - a reference to a possibly cv-qualified such type.
77
+
78
+ [*Example 2*:
79
+
80
+ ``` cpp
81
+ struct C {
82
+ template <typename T>
83
+ C(T);
84
+ };
85
+
86
+ void func(int i) {
87
+ int x = [=](this auto&&) { return i; }(); // OK
88
+ int y = [=](this C) { return i; }(); // error
89
+ int z = [](this C) { return 42; }(); // OK
90
+ }
91
  ```
92
 
93
  — *end example*]
94
 
95
+ The function call operator or operator template is a static member
96
+ function or static member function template [[class.static.mfct]] if the
97
+ *lambda-expression*’s *parameter-declaration-clause* is followed by
98
+ `static`. Otherwise, it is a non-static member function or member
99
+ function template [[class.mfct.non.static]] that is declared `const`
100
+ [[class.mfct.non.static]] if and only if the *lambda-expression*’s
101
+ *parameter-declaration-clause* is not followed by `mutable` and the
102
+ *lambda-declarator* does not contain an explicit object parameter. It is
103
  neither virtual nor declared `volatile`. Any *noexcept-specifier*
104
  specified on a *lambda-expression* applies to the corresponding function
105
  call operator or operator template. An *attribute-specifier-seq* in a
106
  *lambda-declarator* appertains to the type of the corresponding function
107
+ call operator or operator template. An *attribute-specifier-seq* in a
108
+ *lambda-expression* preceding a *lambda-declarator* appertains to the
109
+ corresponding function call operator or operator template. The function
110
+ call operator or any given operator template specialization is a
111
+ constexpr function if either the corresponding *lambda-expression*'s
112
+ *parameter-declaration-clause* is followed by `constexpr` or
113
+ `consteval`, or it is constexpr-suitable [[dcl.constexpr]]. It is an
114
  immediate function [[dcl.constexpr]] if the corresponding
115
  *lambda-expression*'s *parameter-declaration-clause* is followed by
116
  `consteval`.
117
 
118
+ [*Example 3*:
 
 
 
119
 
120
  ``` cpp
121
  auto ID = [](auto a) { return a; };
122
  static_assert(ID(3) == 3); // OK
123
 
 
128
  static_assert(ID(NonLiteral{3}).n == 3); // error
129
  ```
130
 
131
  — *end example*]
132
 
133
+ [*Example 4*:
134
 
135
  ``` cpp
136
  auto monoid = [](auto v) { return [=] { return v; }; };
137
  auto add = [](auto m1) constexpr {
138
  auto ret = m1();
 
157
  static_assert(add(one)(one)() == monoid(2)()); // OK
158
  ```
159
 
160
  — *end example*]
161
 
162
+ [*Note 3*:
163
 
164
+ The function call operator or operator template can be constrained
165
  [[temp.constr.decl]] by a *type-constraint* [[temp.param]], a
166
  *requires-clause* [[temp.pre]], or a trailing *requires-clause*
167
  [[dcl.decl]].
168
 
169
+ [*Example 5*:
170
 
171
  ``` cpp
172
  template <typename T> concept C1 = ...;
173
  template <std::size_t N> concept C2 = ...;
174
  template <typename A, typename B> concept C3 = ...;
 
189
  *lambda-capture* whose constraints (if any) are satisfied has a
190
  conversion function to pointer to function with C++ language linkage
191
  [[dcl.link]] having the same parameter and return types as the closure
192
  type’s function call operator. The conversion is to “pointer to
193
  `noexcept` function” if the function call operator has a non-throwing
194
+ exception specification. If the function call operator is a static
195
+ member function, then the value returned by this conversion function is
196
+ the address of the function call operator. Otherwise, the value returned
197
+ by this conversion function is the address of a function `F` that, when
198
+ invoked, has the same effect as invoking the closure type’s function
199
+ call operator on a default-constructed instance of the closure type. `F`
200
+ is a constexpr function if the function call operator is a constexpr
201
+ function and is an immediate function if the function call operator is
202
+ an immediate function.
203
 
204
  For a generic lambda with no *lambda-capture*, the closure type has a
205
  conversion function template to pointer to function. The conversion
206
  function template has the same invented template parameter list, and the
207
  pointer to function has the same parameter types, as the function call
208
  operator template. The return type of the pointer to function shall
209
  behave as if it were a *decltype-specifier* denoting the return type of
210
  the corresponding function call operator template specialization.
211
 
212
+ [*Note 4*:
213
 
214
  If the generic lambda has no *trailing-return-type* or the
215
  *trailing-return-type* contains a placeholder type, return type
216
  deduction of the corresponding function call operator template
217
  specialization has to be done. The corresponding specialization is that
 
243
  };
244
  ```
245
 
246
  — *end note*]
247
 
248
+ [*Example 6*:
249
 
250
  ``` cpp
251
  void f1(int (*)(int)) { }
252
  void f2(char (*)(int)) { }
253
 
 
259
 
260
  auto glambda = [](auto a) { return a; };
261
  f1(glambda); // OK
262
  f2(glambda); // error: ID is not convertible
263
  g(glambda); // error: ambiguous
264
+ h(glambda); // OK, calls #3 since it is convertible from ID
265
  int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK
266
  ```
267
 
268
  — *end example*]
269
 
270
+ If the function call operator template is a static member function
271
+ template, then the value returned by any given specialization of this
272
+ conversion function template is the address of the corresponding
273
+ function call operator template specialization. Otherwise, the value
274
+ returned by any given specialization of this conversion function
275
+ template is the address of a function `F` that, when invoked, has the
276
+ same effect as invoking the generic lambda’s corresponding function call
277
+ operator template specialization on a default-constructed instance of
278
+ the closure type. `F` is a constexpr function if the corresponding
279
+ specialization is a constexpr function and `F` is an immediate function
280
+ if the function call operator template specialization is an immediate
281
+ function.
282
 
283
+ [*Note 5*: This will result in the implicit instantiation of the
284
  generic lambda’s body. The instantiated generic lambda’s return type and
285
  parameter types are required to match the return type and parameter
286
  types of the pointer to function. — *end note*]
287
 
288
+ [*Example 7*:
289
 
290
  ``` cpp
291
  auto GL = [](auto a) { std::cout << a; return a; };
292
+ int (*GL_int)(int) = GL; // OK, through conversion function template
293
+ GL_int(3); // OK, same as GL(3)
294
  ```
295
 
296
  — *end example*]
297
 
298
  The conversion function or conversion function template is public,
299
  constexpr, non-virtual, non-explicit, const, and has a non-throwing
300
  exception specification [[except.spec]].
301
 
302
+ [*Example 8*:
303
 
304
  ``` cpp
305
  auto Fwd = [](int (*fp)(int), auto a) { return fp(a); };
306
  auto C = [](auto a) { return a; };
307
 
 
313
  ```
314
 
315
  — *end example*]
316
 
317
  The *lambda-expression*’s *compound-statement* yields the
318
+ *function-body* [[dcl.fct.def]] of the function call operator, but it is
319
+ not within the scope of the closure type.
 
 
 
 
320
 
321
+ [*Example 9*:
322
 
323
  ``` cpp
324
  struct S1 {
325
  int x, y;
326
  int operator()(int);
 
345
  constructor and a defaulted move constructor [[class.copy.ctor]]. It has
346
  a deleted copy assignment operator if the *lambda-expression* has a
347
  *lambda-capture* and defaulted copy and move assignment operators
348
  otherwise [[class.copy.assign]].
349
 
350
+ [*Note 6*: These special member functions are implicitly defined as
351
+ usual, which can result in them being defined as deleted. — *end note*]
352
 
353
  The closure type associated with a *lambda-expression* has an
354
  implicitly-declared destructor [[class.dtor]].
355
 
356
  A member of a closure type shall not be explicitly instantiated