-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathP0018_capture_star_this.html
584 lines (519 loc) · 21.6 KB
/
P0018_capture_star_this.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
<html>
<head>
<title>Capturing <tt>*this</tt></title>
<style type="text/css">
blockquote.std { color: #000000; background-color: #F1F1F1;
border: 1px solid #D1D1D1;
padding-left: 0.5em; padding-right: 0.5em; }
blockquote.stddel { text-decoration: line-through;
color: #000000; background-color: #FFA0A0;
border: 1px solid #ECD7EC;
padding-left: 0.5em; padding-right: 0.5em; }
blockquote.stdins { color: #000000; background-color: #A0FFA0;
border: 1px solid #B3EBB3; padding: 0.5em; }
blockquote.stdrepl { color: #000000; background-color: #FFFFA0;
border: 1px solid #EBEBB3; padding: 0.5em; }
ins { background-color:#A0FFA0; text-decoration: none }
del { background-color:#FFA0A0; text-decoration: line-through; }
#hidedel:checked ~ * del, #hidedel:checked ~ * del * { display:none; visibility:hidden }
tab { padding-left: 4em; }
tab3 { padding-left: 3em; }
</style>
</head>
<body>
<HR>
<h2>Lambda Capture of <tt>*this</tt> by Value as <tt>[=,*this]</tt></h2>
<p align=left><b>P0018R4, 2015-11-30</b></p>
<p align=left>
<br/>Authors:
<br/>H. Carter Edwards ([email protected])
<br/>Daveed Vandevoorde ([email protected])
<br/>Christian Trott ([email protected])
<br/>Hal Finkel ([email protected])
<br/>Jim Reus ([email protected])
<br/>Robin Maffeo ([email protected])
<br/>Ben Sander ([email protected])
</p>
<p align=left>
<br/>Audience:
<br/>Evolution Working Group (EWG)
<br/>Core Working Group (CWG)
</p>
<HR>
<h3>Issue: Lambda expressions cannot capture <tt>*this</tt> by value</h3>
<p>
Lambda expressions declared within a non-static member function explicilty
or implicitly captures the <tt>this</tt> pointer to access to member variables
of <tt>this</tt>.
Both capture-by-reference <tt>[&]</tt>
and capture-by-value <tt>[=]</tt>
<i>capture-defaults</i> implicitly capture the <tt>this</tt> pointer,
therefore member variables are always accessed by reference via <tt>this</tt>.
Thus the capture-default has no effect on the capture of <tt>this</tt>.
</p>
<blockquote class="std"><tt>
struct S {<br/>
<tab>int x ;<br/>
<tab>void f() {<br/>
<tab><tab>// The following lambda captures are currently identical<br/>
<tab><tab>auto a = [&]() { x = 42 ; } // OK: transformed to (*this).x<br/>
<tab><tab>auto b = [=]() { x = 43 ; } // OK: transformed to (*this).x<br/>
<tab><tab>a();<br/>
<tab><tab>assert( x == 42 );<br/>
<tab><tab>b();<br/>
<tab><tab>assert( x == 43 );<br/>
<tab>}<br/>
};<br/>
</tt>
</blockquote>
<p>
Asynchronous dispatch of closures is a cornerstone of parallelism
and concurrency.
When a lambda is asynchronously dispatched from within a
non-static member function, via <tt>std::async</tt>
or other concurrency / parallelism dispatch mechanism,
the <tt>*this</tt> object <i>cannot</i> be captured by value.
Thus when the <tt>std::future</tt> (or other handle) to the dispatched lambda
outlives the originating class the lambda's captured <tt>this</tt>
pointer is invalid.
</p>
<blockquote class="std"><tt>
class Work {</br>
private:</br>
<tab>int value ;</br>
public:</br>
<tab>Work() : value(42) {}</br>
<tab>std::future<int> spawn()</br>
<tab> { return std::async( [=]()->int{ return value ; }); }</br>
};</br>
</br>
std::future<int> foo()</br>
{</br>
<tab>Work tmp ;</br>
<tab>return tmp.spawn();</br>
<tab>// The closure associated with the returned future</br>
<tab>// has an implicit this pointer that is invalid.</br>
}</br>
</br>
int main()</br>
{</br>
<tab>std::future<int> f = foo();</br>
<tab>f.wait();</br>
<tab>// The following fails due to the</br>
<tab>// originating class having been destroyed</br>
<tab>assert( 42 == f.get() );</br>
<tab>return 0 ;</br>
}</br>
</tt></blockquote>
<p>
Current and future hardware architectures
specifically targeting parallelism and concurrency have
heterogeneous memory systems.
For example, NUMA regions, attached accelerator memory, and
processing-in-memory (PIM) stacks.
In these architectures it will often result in significantly
improved performance if the closure is copied to the
data upon which it operates, as opposed to moving
the data to and from the closure.
</p>
<p>
For example, parallel execution of a closure on large data
spanning NUMA regions will be more performant if a copy
of that closure residing in the same NUMA region acts
upon that data.
If a full (self-contained) capture-by-value lambda closure
were given to a parallel dispatch, such as in the
parallelism technical specification, then the library could
create copies of that closure within each NUMA region to improve
data locality for the parallel computation.
For another example, a closure dispatched to an attached accelerator
with separate memory must be copied to the accelerator's
memory before execution can occur.
Thus current and future architectures *require* the capability
to copy closures to data.
</p>
<h3>Error-prone and onerous work-around: <tt>[=,tmp=*this]</tt></h3>
<p>
A potential work-around for this deficiency is to explicitly
capture a copy the originating class.
</p>
<blockquote class="std"><tt>
class Work {</br>
private:</br>
<tab>int value ;</br>
public:</br>
<tab>Work() : value(42) {}</br>
<tab>std::future<int> spawn()</br>
<tab>{</br>
<tab><tab>return std::async( [=,tmp=*this]()->int{ return tmp.value ; });</br>
<tab>}</br>
};</br>
</tt></blockquote>
<p>
This work-around has two liabilities.
First, the <tt>this</tt> pointer is also captured which provides
a significant opportunity to erroneously reference a
<tt>this-></tt><i>member</i> instead of a <tt>tmp.</tt><i>member</i>
as there are two distinct objects in the closure that
reference two distinct <i>member</i> of the same name.
Second, it is onerous and counter-productive
to the introduction of asynchronously dispatched lambda expressions
within existing code.
Consider the case of replacing a <tt>for</tt> loop within a
non-static member function with a <i>parallel for each</i> construct
as in the parallelism technical specification.
</p>
<blockquote class="std"><tt>
class Work {</br>
public:</br>
<tab>void do_something() const {</br>
<tab><tab>// for ( int i = 0 ; i < N ; ++i )</br>
<tab><tab>foreach( Parallel , 0 , N , [=,tmp=*this]( int i )</br>
<tab><tab>{</br>
<tab><tab><tab>// A modestly long loop body where</br>
<tab><tab><tab>// every reference to a member must be modified</br>
<tab><tab><tab>// for qualification with 'tmp.'</br>
<tab><tab><tab>// Any mistaken omissions will silently fail</br>
<tab><tab><tab>// as references via 'this->'.</br>
<tab><tab>}</br>
<tab><tab>);</br>
<tab>}</br>
};</br>
</tt></blockquote>
<p>
In this example every reference to a member
in the pre-existing code must be modified to
add the <tt>tmp.</tt> qualification.
This onerous process must be repeated throughout
an existing code base.
A full lambda capture of <tt>*this</tt> would eliminate
such an onerous and silent-error-prone process of
injecting parallelism
and concurrency into an large, existing code base.
<p>
As currently specified integration of lambda and concurrency
capabilities is perilous, as demonstrated by the previous <tt>Work</tt> example.
A lambda generated within a non-static member function <i>cannot</i>
be a full (self-contained) closure and therefore cannot reliably
be used with an asynchronous dispatch.
</p>
<p>
Lambda capability is a significant boon to productivity,
especially when parallel or concurrent closures can be
defined with lambdas as opposed to manually generated functors.
If the capability to capture <tt>*this</tt> by value
is not enabled then the productivity benefits of lambdas
cannot be fully realized in the parallelism and concurrency domain.
</p>
<BR><BR><HR>
<h3>Proposed Wording Changes (Approach #1)</h3>
<p><strong>Note 1: </strong> The wording below takes the approach of treating
captures of the form "<tt>* this</tt>" as a kind of "capturing of
<tt>this</tt>", and distinguising "full capture" (i.e., copying the
<tt>*this</tt> value) from "partial capture" (copying just the pointer).
A second approach, presented below, instead phrases it in
terms of the form "<tt>* this</tt>" capturing the entity pointed to by the
<tt>this</tt> pointer. Although I prefer the first
approach some early reviewers preferred the second.</p>
<p><strong>Note 2: </strong>I use "<tt>* this</tt>" (with quotation
marks and an
intervening space) when referring to the form of the capture and
<tt>*this</tt> when referring to an implied expression.
</p>
<input type="checkbox" id="hidedel">Hide deleted text</input>
<p>In 5.1.2/1, extend the production for <i>simple-capture</i> as follows:</p>
<blockquote class="std">
<blockquote class="grammar">
…<br/>
<i>simple-capture:</i><br/>
<tab><i>identifier</i><br/>
<tab><tt>&</tt> <i>identifier</i><br/>
<tab><tt>this</tt><br/>
<tab><ins><tt>* this</tt></ins><br/>
…<br/>
</blockquote>
</blockquote>
<p>Modify 5.1.2/8 as follows:</p>
<blockquote class="std">
…<br/>
If a <i>lambda-capture</i> includes a <i>capture-default</i> that is
<tt>=</tt>, each <i>simple-capture</i> of that <i>lambda-capture</i> shall be
of the form "<tt>&</tt> <i>identifier</i>"<ins> or "<tt>* this</tt>"</ins>.
<br/>
…<br/>
[ <i>Example:</i>
<blockquote><tt>
<tab>struct S2 { void f(int i); };<br/>
<tab>void S2::f(int i) {<br/>
<tab><tab> [&, i]{ };
<tab>  // </tt><i>OK</i><tt><br/>
<tab><tab> [&, &i]{ };
<tab> // </tt><i>error: </i><tt>i</tt><i> preceded by
</i><tt>&</tt><i> when </i><tt>&</tt><i> is the default</i><tt><br/>
<tab><tab> <ins>[=, *this]{ };
     // </tt><i>OK</i><tt></ins><br/>
<tab><tab> [=, this]{ };
<tab>// </tt><i>error: </i><tt>this</tt><i> when </i><tt>=</tt><i>
is the default</i><tt><br/>
<tab><tab> [i, i]{ };
<tab>  // </tt><i>error:</i><tt> i </tt><i>repeated</i><tt><br/>
<tab><tab> <ins>[this, *this]{ };
  // </tt><i>error:</i><tt> this </tt><i>appears twice</i></ins><br/>
<tab>}
</tt></blockquote>
—<i>end example</i> ]
</blockquote>
<p>Modify 5.1.2/10 as follows:</p>
<blockquote class="std">
…<br/>
An entity that is designated by a <i>simple-capture</i> is said to be
<i>explicitly captured</i>, and shall be <tt>this</tt> <ins>(when the
<i>simple-capture</i> is "<tt>this</tt>" or "<tt>* this</tt>")</ins>
or a variable with automatic storage duration
declared in the reaching scope of the local lambda expression.
<ins>A <i>simple-capture</i> of the form "<tt>* this</tt>" is called
<i>a full capture of <tt>this</tt></i>; all other ways to capture
<tt>this</tt> are called <i>partial captures of <tt>this</tt></i>.</ins>
<br/>
…<br/>
</blockquote>
<p>Add to the example of 5.1.2/13:</p>
<blockquote class="stdins">
<blockquote><tt>
<tab>struct s2 {<br/>
<tab><tab>double ohseven = .007;<br/>
<tab><tab>auto f() {<br/>
<tab><tab><tab>return [this]{<br/>
<tab><tab><tab><tab>return [*this]{<br/>
<tab><tab><tab><tab><tab> return ohseven; // </tt><i>OK</i><tt><br/>
<tab><tab><tab><tab>}<br/>
<tab><tab><tab>}();<br/>
<tab><tab>}<br/>
<tab><tab>auto g() {<br/>
<tab><tab><tab>return []{<br/>
<tab><tab><tab><tab>return [*this]{} //
</tt><i>error: </i><tt>this</tt>
<i> not captured by outer lambda-expression</i><tt><br/>
<tab><tab><tab>}();<br/>
<tab><tab>}<br/>
<tab>};<br/>
</tt></blockquote>
</blockquote>
<p>Modify 5.1.2/15 as follows:</p>
<blockquote class="std">
…<br/>
The type of such a data member is the type of the corresponding captured
entity if the entity is not a reference to an object, or the referenced
type otherwise<ins>, except that for a full capture of <tt>this</tt> the type
is the (possibly cv-qualified) type of <tt>*this</tt></ins>.
<br/>
…<br/>
</blockquote>
<p>Move 5.1.2/18 to immediately follow 5.1.2/15 and modify it as follows:</p>
<blockquote class="std">
…<br/>
If <tt>this</tt> is captured, each odr-use of <tt>this</tt> is transformed
into <ins>(a) a pointer to the corresponding unnamed data member in the
case of a full capture of <tt>this</tt>, or (b)</ins> an access to the
corresponding unnamed data member of the closure type, cast (5.4) to the
type of <tt>this</tt><ins> in the case of a partial capture of
<tt>this</tt></ins>.
<br/>
…<br/>
</blockquote>
<p>Modify 5.1.2/17 as follows:</p>
<blockquote class="std">
If a <i>lambda-expression</i> <tt>m2</tt> captures an entity and that entity
is captured by an immediately enclosing <i>lambda-expression</i> <tt>m1</tt>,
then <tt>m2</tt>'s capture is transformed as follows:
<ul>
<li>if <tt>m1</tt> captures the entity by copy, <tt>m2</tt> captures the
corresponding non-static data member of <tt>m1</tt>'s closure type
<ins>(a pointer to <tt>m1</tt>'s member if it corresponds to a full
capture of <tt>this</tt> [<i>Note:</i> that pointer corresponds to the
captured value of the <tt>this</tt> pointer, and may be used to compute
<tt>*this</tt> if <tt>m2</tt>
also fully captures <tt>this</tt>. <i>—end note</i>])</ins>;</li>
<li>if <tt>m1</tt> captures the entity by reference, <tt>m2</tt> captures
the same entity captured by <tt>m1</tt>.
</ul>
<br/>
…<br/>
</blockquote>
<p>Modify 5.1.2/23 as follows:</p>
<blockquote class="std">
…<br/>
When the <i>lambda-expression</i> is evaluated, the entities that are captured
by copy are used to direct-initialize each corresponding non-static data member
of the resulting closure object, <ins>except that the entity is replaced by
<tt>*this</tt> in the case of a (possibly transformed) full capture of
<tt>this</tt>;</ins><del>and</del> the non-static data members corresponding
to the init-captures are initialized as indicated by the corresponding
initializer (which may be copy- or direct-initialization).
<br/>
…<br/>
</blockquote>
<BR>
<h3>Proposed Wording Changes (Approach #2)</h3>
<p>In 5.1.2/1, extend the production for <i>simple-capture</i> as follows:</p>
<blockquote class="std">
<blockquote class="grammar">
…<br/>
<i>simple-capture:</i><br/>
<tab><i>identifier</i><br/>
<tab><tt>&</tt> <i>identifier</i><br/>
<tab><tt>this</tt><br/>
<tab><ins><tt>* this</tt></ins><br/>
…<br/>
</blockquote>
</blockquote>
<p>Modify 5.1.2/8 as follows:</p>
<blockquote class="std">
…<br/>
If a <i>lambda-capture</i> includes a <i>capture-default</i> that is
<tt>=</tt>, each <i>simple-capture</i> of that <i>lambda-capture</i> shall be
of the form "<tt>&</tt> <i>identifier</i>"<ins> or "<tt>* this</tt>"</ins>.
<br/>
…<br/>
[ <i>Example:</i>
<blockquote><tt>
<tab>struct S2 { void f(int i); };<br/>
<tab>void S2::f(int i) {<br/>
<tab><tab> [&, i]{ };
<tab>  // </tt><i>OK</i><tt><br/>
<tab><tab> [&, &i]{ };
<tab> // </tt><i>error: </i><tt>i</tt><i> preceded by
</i><tt>&</tt><i> when </i><tt>&</tt><i> is the default</i><tt><br/>
<tab><tab> [=, *this]{ };
     // </tt><i>OK</i><tt><br/>
<tab><tab> [=, this]{ };
<tab>// </tt><i>error: </i><tt>this</tt><i> when </i><tt>=</tt><i>
is the default</i><tt><br/>
<tab><tab> [i, i]{ };
<tab>  // </tt><i>error: </i><tt>i</tt><i> repeated</i><tt><br/>
<tab><tab> <ins>[this, *this]{ };
  // </tt><i>error: </i><tt>this</tt><i> appears
twice</i></ins><tt><br/>
<tab>}
</tt></blockquote>
—<i>end example</i> ]
</blockquote>
<p>Replace 5.1.2/10:</p>
<blockquote class="stddel">
The <i>identifier</i> in a simple-capture</i> is looked up using the usual
rules for unqualified name lookup (3.4.1); each such lookup shall find an
entity. An entity that is designated by a <i>simple-capture</i> is said to
be <i>explicitly captured</i>, and shall be <tt>this</tt> or a variable with
automatic storage duration declared in the reaching scope of the local
lambda expression.
</blockquote>
<p>by:</p>
<blockquote class="stdins">
Each <i>simple-capture</i> designates an entity (described next), which is
said to be <i>explicitly captured</i>. For a <i>simple-capture</i> of the
form "<tt>this</tt>" or "<tt>* this</tt>" the entity is <tt>this</tt> or
<tt>*this</tt>, respectively. For a <i>simple-capture</i> of the form
"<i>identifier</i>" or "<tt>&</tt> <i>identifier</i>" the <i>identifier</i>
is looked up using the usual rules for unqualified name lookup (3.4.1) and
each such lookup shall find a variable with automatic storage duration
declared in the reaching scope of the local lambda expression; that variable
is the entity designated by the <i>simple-capture</i>.
</blockquote>
<p>Modify 5.1.2/12 as follows:</p>
<blockquote class="std">
A <i>lambda-expression</i> with an associated <i>capture-default</i> that
does not explicitly capture <tt>this</tt><ins>, <tt>*this</tt>,</ins> or a
variable with automatic storage duration (this excludes any
<i>id-expression</i> that has been found to refer to an
<i>init-capture</i>'s associated non-static data member), is said to
implicitly capture the entity (i.e., <tt>this</tt><ins>,
<tt>*this</tt>,</ins> or a variable) if the <i>compound-statement</i>:<br/>
…<br/>
</blockquote>
<p>Modify 5.1.2/13 as follows:</p>
<blockquote class="std">
…<br/>
If <tt>this</tt><ins> or <tt>*this</tt></ins> is captured by a local lambda
expression, its nearest enclosing function shall be a non-static member
function. If a <i>lambda-expression</i> or an instantiation of the
function call operator template of a generic lambda odr-uses (3.2)
<del><tt>this</tt> or </del>a variable with automatic storage duration
from its reaching scope, that <del>entity</del><ins>variable</ins> shall be
captured by the <i>lambda-expression</i>.
<ins>If a <i>lambda-expression</i> or an instantiation of the
function call operator template of a generic lambda odr-uses (3.2)
<tt>this</tt> then either <tt>this</tt> or <tt>*this</tt> shall be
captured by the <i>lambda-expression</i>.</ins>
If a lambda-expression captures an entity and that entity
<ins>(or, alternatively, <tt>this</tt> if the entity is <tt>*this</tt>)</ins>
is not defined or captured in the immediately enclosing lambda expression
or function, the program is ill-formed.<br/>
…<br/>
</blockquote>
<p>and add to the example</p>
<blockquote class="stdins">
<blockquote><tt>
<tab>struct s2 {<br/>
<tab><tab>double ohseven = .007;<br/>
<tab><tab>auto f() {<br/>
<tab><tab><tab>return [this]{<br/>
<tab><tab><tab><tab>return [*this]{<br/>
<tab><tab><tab><tab><tab> return ohseven; // </tt><i>OK</i><tt><br/>
<tab><tab><tab><tab>}<br/>
<tab><tab><tab>}();<br/>
<tab><tab>}<br/>
<tab><tab>auto g() {<br/>
<tab><tab><tab>return []{<br/>
<tab><tab><tab><tab>return [*this]{} //
</tt><i>error: neither </i><tt>this</tt><i> nor </i><tt>*this</tt>
<i> captured by outer lambda-expression</i><tt><br/>
<tab><tab><tab>}();<br/>
<tab><tab>}<br/>
<tab>};<br/>
</tt></blockquote>
</blockquote>
<p>Modify 5.1.2/17 as follows (note that the last inserted sentence in this
paragraph is a useful clarification independently of the feature being
specified):</p>
<blockquote class="std">
<ins>Let <tt>m1</tt> be a <i>lambda-expression</i> immediately enlosing
another <i>lambda-expression</i> <tt>m2</tt>.</ins>
If <del>a <i>lambda-expression</i> </del><tt>m2</tt> captures an entity and
that entity is captured by <del>an immediately enclosing
<i>lambda-expression</i> </del><tt>m1</tt>,
then <tt>m2</tt>'s capture is transformed as follows:
<ul>
<li>if <tt>m1</tt> captures the entity by copy, <tt>m2</tt> captures the
corresponding non-static data member of <tt>m1</tt>'s closure
type;</li>
<li>if <tt>m1</tt> captures the entity by reference, <tt>m2</tt> captures
the same entity captured by <tt>m1</tt>.
</ul>
<ins>
Furthermore, if <tt>m1</tt> captures <tt>this</tt> and <tt>m2</tt>
captures <tt>*this</tt>, then <tt>m2</tt> captures the object pointed to
by the non-static data member of <tt>m1</tt>'s closure type corresponding
to the capture of <tt>this</tt>. Similarly, if <tt>m1</tt> captures
<tt>*this</tt> and <tt>m2</tt> captures <tt>this</tt>, then <tt>m2</tt>
captures a pointer to the non-static data member of <tt>m1</tt>'s closure
type corresponding to the capture of <tt>*this</tt>.
If any of these transformations applies to a capture of <tt>this</tt> or
<tt>*this</tt>, the transformed capture is still considered a capture of,
respectively, <tt>this</tt> or <tt>*this</tt> in what follows.</ins>
<br/>
…<br/>
</blockquote>
<p>Modify 5.1.2/18 as follows:</p>
<blockquote class="std">
…<br/>
If <tt>this</tt> is captured, each odr-use of <tt>this</tt> is transformed
into an access to the corresponding unnamed data member of the closure type,
cast (5.4) to the type of <tt>this</tt>.
<ins>Similarly, if <tt>*this</tt> is captured, each odr-use of <tt>this</tt>
is transformed into a pointer to the corresponding unnamed data member of
the closure, cast (5.4) to the type of <tt>this</tt>.</ins>
<br/>
…<br/>
</blockquote>
</body>
</html>