From Jason Turner

[expr.prim.lambda.closure]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmp8n0nkpz9/{from.md → to.md} +288 -0
tmp/tmp8n0nkpz9/{from.md → to.md} RENAMED
@@ -0,0 +1,288 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #### Closure types <a id="expr.prim.lambda.closure">[[expr.prim.lambda.closure]]</a>
2
+
3
+ The type of a *lambda-expression* (which is also the type of the closure
4
+ object) is a unique, unnamed non-union class type, called the *closure
5
+ 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; };
50
+ bool b = glambda(3, 3.14); // OK
51
+
52
+ auto vglambda = [](auto printer) {
53
+ return [=](auto&& ... ts) { // OK: ts is a function parameter pack
54
+ printer(std::forward<decltype(ts)>(ts)...);
55
+
56
+ return [=]() {
57
+ printer(ts ...);
58
+ };
59
+ };
60
+ };
61
+ auto p = vglambda( [](auto v1, auto v2, auto v3)
62
+ { std::cout << v1 << v2 << v3; } );
63
+ auto q = p(1, 'a', 3.14); // OK: outputs 1a3.14
64
+ q(); // OK: outputs 1a3.14
65
+ ```
66
+
67
+ — *end example*]
68
+
69
+ The function call operator or operator template is declared `const` (
70
+ [[class.mfct.non-static]]) if and only if the *lambda-expression*’s
71
+ *parameter-declaration-clause* is not followed by `mutable`. It is
72
+ neither virtual nor declared `volatile`. Any *noexcept-specifier*
73
+ 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
88
+ auto ID = [](auto a) { return a; };
89
+ 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*:
101
+
102
+ ``` cpp
103
+ auto monoid = [](auto v) { return [=] { return v; }; };
104
+ auto add = [](auto m1) constexpr {
105
+ auto ret = m1();
106
+ return [=](auto m2) mutable {
107
+ auto m1val = m1();
108
+ auto plus = [=](auto m2val) mutable constexpr
109
+ { return m1val += m2val; };
110
+ ret = plus(m2());
111
+ return monoid(ret);
112
+ };
113
+ };
114
+ constexpr auto zero = monoid(0);
115
+ constexpr auto one = monoid(1);
116
+ static_assert(add(one)(zero)() == one()); // OK
117
+
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
153
+ instantiation of the function call operator template with the same
154
+ template arguments as those deduced for the conversion function
155
+ template. Consider the following:
156
+
157
+ ``` cpp
158
+ auto glambda = [](auto a) { return a; };
159
+ int (*fp)(int) = glambda;
160
+ ```
161
+
162
+ The behavior of the conversion function of `glambda` above is like that
163
+ of the following conversion function:
164
+
165
+ ``` cpp
166
+ struct Closure {
167
+ template<class T> auto operator()(T t) const { ... }
168
+ template<class T> static auto lambda_call_operator_invoker(T a) {
169
+ // forwards execution to operator()(a) and therefore has
170
+ // the same return type deduced
171
+ ...
172
+ }
173
+ template<class T> using fptr_t =
174
+ decltype(lambda_call_operator_invoker(declval<T>())) (*)(T);
175
+
176
+ template<class T> operator fptr_t<T>() const
177
+ { return &lambda_call_operator_invoker; }
178
+ };
179
+ ```
180
+
181
+ — *end note*]
182
+
183
+ [*Example 4*:
184
+
185
+ ``` cpp
186
+ void f1(int (*)(int)) { }
187
+ void f2(char (*)(int)) { }
188
+
189
+ void g(int (*)(int)) { } // #1
190
+ void g(char (*)(char)) { } // #2
191
+
192
+ void h(int (*)(int)) { } // #3
193
+ void h(char (*)(int)) { } // #4
194
+
195
+ auto glambda = [](auto a) { return a; };
196
+ f1(glambda); // OK
197
+ f2(glambda); // error: ID is not convertible
198
+ g(glambda); // error: ambiguous
199
+ h(glambda); // OK: calls #3 since it is convertible from ID
200
+ int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK
201
+ ```
202
+
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)
222
+ ```
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);
260
+ void f() {
261
+ [=]()->int {
262
+ return operator()(this->x + y); // equivalent to S1::operator()(this->x + (*this).y)
263
+ // this has type S1*
264
+ };
265
+ }
266
+ };
267
+ ```
268
+
269
+ — *end example*]
270
+
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
+