-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathFreePacks.html
531 lines (425 loc) · 30.8 KB
/
FreePacks.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
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head>
<style type="text/css">
body { color: #000000; background-color: #FFFFFF; }
ins, ins * { text-decoration:none; font-weight:bold; background-color:#A0FFA0 }
del, del * { text-decoration:line-through; background-color:#FFA0A0 }
#hidedel:checked ~ * del, #hidedel:checked ~ * del * { display:none; visibility:hidden }
p, li, blockquote {
font-family: "sans", Times, serif;
font-size: 11pt
}
h1, h2, h3 {font-family: "sans", Times, serif;}
h4 {font-family: "sans", Times, serif; margin-top:0.25em;}
p.example { margin-left: 2em; }
pre.example { margin-left: 2em; }
div.example { margin-left: 2em; }
code.extract { background-color: #F5F6A2; }
pre.extract { margin-left: 2em; background-color: #FFFFFF;
border: 1px solid #E1E28E; font-family: "monospace"; }
p.function { }
.attribute { margin-left: 2em; }
.attribute dt { float: left; font-style: italic;
padding-right: 1ex; }
.attribute dd { margin-left: 0em; }
blockquote.std { color: #000000; background-color: #F1F1F1;
border: 1px solid #D1D1D1;
padding-left: 0.5em; padding-right: 0.5em; padding-bottom: 0.25em }
blockquote.stddel { text-decoration: line-through;
color: #000000; background-color: #FFEBFF;
border: 1px solid #ECD7EC;
padding-left: 0.5empadding-right: 0.5em; ; }
blockquote.stdins, code.ins {
color: #000000; background-color: #C8FFC8;
border: 1px solid #B3EBB3; padding: 0.5em; padding-top:0; }
blockquote pre em { font-family: normal }
table { border: 1px solid black; border-spacing: 0px;
margin-left: auto; margin-right: auto; }
th { text-align: left; vertical-align: top;
padding-left: 0.8em; border: none; }
td { text-align: left; vertical-align: top;
padding-left: 0.8em; border: none; }
ul { list-style-type: none; }
a { text-decoration: none; }
ul > li:before {
content: "\2014";
position: absolute;
margin-left: -1.5em;
}
p.grammarlhs { font-style:italic; margin-bottom: 0; margin-top: 0em }
p.grammarrhs { font-style:italic; margin-left:8em; margin-top:0; margin-bottom: 0; text-indent:-4em }
p.grammarrrhs { font-style:italic; margin-left:12em; margin-top:0; margin-bottom: 0; text-indent:-4em }
p.grammarlhs tt { font-style:normal }
p.grammarrhs tt { font-style:normal }
p.grammarrrhs tt { font-style:normal }
</style>
<title>Proposal: free packs</title>
</head><body>
<div style="text-align: right; float: right;">
<p>ISO/IEC JTC1 SC22 WG21, Evolution Working Group<br>
DxxxxR0<br>
Robert Haberlach (rh633{at}cam{dot}ac.uk)<br>
2016-06-28</p>
</div>
<h2>Free packs</h2>
<p>Parameter packs were introduced with C++11 and have proven to be an immensely useful tool, particularly in generic programming.
However, their introduction is only possible via a (deduced) template parameter, which often makes for tedious circumlocutions.
We discuss syntax and design of "free" packs that can be declared and retrieved ad hoc, and provide corresponding wording.
<br><br>This topic is also discussed in P0341.<sup><a href="#P0341">[P0341]</a></sup>
Our proposal presents a similar, but more concrete approach.</p>
<h3>Motivation</h3>
<p>Consider the following template that transforms a tuple given a functor (skipped perfect forwarding for the sake of simplicity): </p>
<pre class="extract"><code>template <size_t... indices, typename T, typename Func>
auto transform(T t, Func f, index_sequence<indices...>) {
return make_tuple(f(get<indices>(t))...);
}
template <typename... T, typename Func>
auto transform(std::tuple<T...> t, Func f) {
return transform(t, f, index_sequence_for<T...>{});
}</code></pre>
<p>We introduced a complete second template solely for <tt>indices</tt>, a pack of indices for each of the tuple's elements.
We need such a pack; but the only practical way it can be obtained is by having it deduced from what <tt>make_index_sequence</tt> gives.</p>
<p>This occurs over and over in code that operates on tuples or packs - if the reader visits an arbitrary Stackoverflow question about variadic templates or tuples,
she has a good chance of seeing this technique demonstrated.
<sup><a href="#SO1">[SO1]</a></sup><sup><a href="#SO2">[SO2]</a></sup><sup><a href="#SO3">[SO3]</a></sup><sup><a href="#SO4">[SO4]</a></sup><sup><a href="#SO5">[SO5]</a></sup>
Introducing free packs would simplify a lot of meta programming code.</p>
<h3>Scope</h3>
<p>Free packs will be a new kind of entity that can be defined at namespace scope, block scope or class scope. There are three variants:</p>
<ul><li><b>Value packs</b> are packs of objects or references, subject to all usual declaration specifiers (specifically <tt>constexpr</tt>). There are non-static data member packs, too. </li>
<li><b>Type packs</b> are packs of types. Simples.</li>
<li><b>Pack templates</b> are templates of packs, i.e. their specializations can be expanded. </li></ul>
<p>Template packs (that is, packs of template names) are not proposed for reasons described below. </p>
<h3>Syntax</h3>
<h4>Value packs</h4>
<p>…will be declared in the exact same manner as function parameter packs, with no unexpanded parameter packs necessary.
They are not allowed as function parameters (which would clash with the grammar, anyway, due to the syntax for variadic functions with no comma preceding the ellipsis).</p>
<p>We simultaneously propose initializers for packs (which also appertain to template and function parameter packs):</p>
<pre class="extract"><code class="c++">int... i = {1, 2, 3}; // Ok: pack of size 3
int... j{1, 2, 3}; // Ok: pack of size 3
int ...h{}, l; // Ok: empty pack and bog-standard int named l
template <typename... T>
T... t = {(std::void_t<T>(), 0)...}; // Ok: pack of size sizeof...(T), all initialized with 0
</code></pre>
<p>In the last example, we have shown the syntax for declaring a pack that is an expansion itself. Since the pack initializer still appertains to the entire pack
(not individual declarators generated), we must ensure that the length of the initializer list is appopriate ourselves. (The above can be made syntactically nicer by using an
auxiliary function template <tt>for_</tt>, in which case the initializer becomes <tt>{ for_<T>(0)... }</tt>). (See also core issue 1520.<sup><a href="#CWG1520">[CWG1520]</a></sup>)</p>
<p>As under current gammar, the ellipsis appertains to the declarator. The <em>init-declarator</em> must be copy-list-initialized,
either with a list of expressions implicitly convertible to the value pack's element type(s), or with a list of types that will be the type pack's contents. </p>
<h4>Type packs</h4>
<p>…have the following syntax:</p>
<pre class="extract"><code>using... t = {int, float, void};
</code></pre>
<p>The semantics are very similar to those of usual <em>alias-declaration</em>s;
in particular, the type list shall not define a class or enumeration if the declaration is a <em>template-declaration</em>,
and the point of declaration of the identifier is after the <em>braced-init-list</em>.</p>
<h3>Design</h3>
<pre class="extract"><code class="c++">// Example definitions:
template <size_t n>
constexpr size_t... make_indices = {make_indices<n/2>..., (make_indices<(n+1)/2> + n/2)...};
template <> constexpr size_t... make_indices<1> = {0};
template <> constexpr size_t... make_indices<0> = {};
template <typename... T>
constexpr size_t... indices_for = {make_indices<sizeof...(T)>...};
struct X {
int... i{1, 2};
X(int a, int b) : i{a, b} {}
// X(int a) : i{a} () // error: inconsistent length given by constructors/mem-initializers
};
</code></pre>
<p>The size of the pack must be inferred, and it is either from the length of the initializer list, or from the length of an unexpanded pack within the
<em>decl-specifier-seq</em>, or from a <em>mem-initializer</em> in a constructor (or both, in which case the length's must coincide). </p>
<p>Note that initializers for value packs are only necessary when the pack is not a non-static data member, and its type does not contain an unexpanded pack,
because in such cases, the pack must be empty, which is better indicated with <tt>= {}</tt>. </p>
<p>Now consider our transform template's new implementation:</p>
<pre class="extract"><code class="c++">template <typename... T, typename Func>
auto transform(std::tuple<T...> t, Func f) {
return make_tuple(f(get<indices_for<T...>>(t))...);
}</code></pre>
This could be further simplified if <tt>tuple</tt> was given a static data member pack <tt>indices</tt>:
<pre class="extract"><code class="c++">template <typename... T, typename Func>
auto transform(std::tuple<T...> t, Func f) {
return make_tuple(f(get<t....indices>(t))...);
}</code></pre>
<p>Or consider one of P0341's examples:</p>
<pre class="extract"><code class="c++">template <int> struct accept_all {
accept_all(auto&&);
};
template <size_t i, typename U, typename... T>
U&& ith_argument(accept_all<get_indices<i>>..., U&& u, T&&...) {
return std::forward<U>(u);}</code></pre>
<h4>Pack templates</h4>
<p>Demonstrated above are type pack templates, the semantics of which are defined to be very similar to alias templates: They don't introduce a <em>template-id</em> (and thus cannot be
specialized), and they allow for the usual deduction for function templates:
<pre class="extract"><code>template <typename T>
typename... forwarding_ref = {T&&, T&};
template <typename T>
void f(forwarding_ref<T>...);
int i;
f(0, i); // Ok: T = int</code></pre>
</p>
<h4>Template packs?</h4>
<p>There has been far less clamor for template packs than both type and value packs, which by contrast have definite applications (some of which are outlined in this proposal).
They do not go well with pack templates; partly because they create the notion of a “template template”, leading to abhorrent invocation syntax
in dependent contexts: </p>
<pre class="extract"><code>template <int> struct A {};
struct X {
template <typename>
template <int> struct pack = {A, A, A};
};
template <typename T>
struct Y {
typename... t = {typename T::template ... template pack<int><0>...};
};
</code></pre>
<p>To avoid such monstrosities, template packs must be restricted to an extent that would make the design appear inconsistent. We therefore do not propose template packs. </p>
<h4>Non-static data packs</h4>
<p>One of the core ideas of P0341 are non-static data member packs, as in this simple implementation of a tuple (which is also subpar, because it stores empty classes):</p>
<pre class="extract"><code>template <typename... T> struct tuple {
T... values;
};</code></pre>
<p>The fundamental issue is that we need to commit on a length of the pack somehow. We cannot use <em>mem-initializer</em>s, because different
specializations of constructor templates could yield different lengths. Instead, either</p>
<ul><li>the type contains an unexpanded pack, or</li></ul>
<h4>A syntactical disambiguator in dependent contexts analogous to <tt>:: template</tt></h4>
<p>As pointed out by Douglas Gregor back when this feature was first proposed in similar form,<sup><a href="#COMP1">[COMP1]</a></sup>
allowing member packs - as this proposal does - implies that we cannot per se know whether a dependent
<em>qualified-id</em> names e.g. a value or a pack of values. Consider </p>
<pre class="extract"><code>template <typename T1, typename T2> void f() {
foo(T1::members + T2::members...);
}</code></pre>
<p>Both <tt>T1::members</tt> and <tt>T2::members</tt> could be packs, simultaneously or only one at a time.
Although such pack expansions would not be technically problematic, they can make code harder to comprehend; the three aforementioned possibilities
will all produce a well-formed instantiated function, having three different meanings.</p>
<p>However, the problems go further than syntactic meaningfulness. Consider</p>
<pre class="extract"><code>template <typename T1, int... v> void g() {
foo(T1::members + v...);
}</code></pre>
<p>Prior to the introduction of free packs, this code unambiguously adds </p>
<p>The next example demonstrates the only context in the language in which there is an ambiguity between a pack expansion and another construct (an ellipsis indicating that the
function is variadic):</p>
<pre class="extract"><code class="c++">template <typename T> struct ParamPackOrEllipsis {
void h(typename T::members...); // variadic function or pack expansion?
};</code></pre>
<p>In order to avoid this, we need to mark the dependent names intended for packs separately. The syntax we propose is the following:</p>
<ol><li><p>“<tt>T::... x</tt>” and “<tt>T. ...x</tt>” for a value pack (the latter would not work if the white space between the dot and the ellipsis was removed, since the maximum munch rule would make it parse as “<tt>T... .x</tt>”),</p></li>
<li><p>“<tt>typename T::... x</tt>” for a type pack, and</p></li>
<li><p>“<tt>T::... template x</tt>” for a template pack.</p></li></ol>
<p>When we refer to a pack template, the <tt>template</tt> keyword is prepended to the ellipsis, i.e. “<tt>T::template... x</tt>” and
“<tt>typename T::template... x</tt>” are names for corresponding pack templates. </p>
<pre class="extract"><code></code></pre>
<h3>Wording</h3>
<p>3 [basic] ¶3:</p>
<blockquote class="std">An entity is a value, object, reference, function, enumerator, type, class member,
bit-field, template, template specialization, namespace, or <del>parameter</del> pack.</blockquote>
<p>3.2 [basic.def.odr] ¶2:</p>
<blockquote class="std">A <em>declaration</em> is a definition unless it declares<br>
…,<br>
(2.17) — […], <del>or</del><br>
(2.18) — […]<del>.</del><ins>, or</ins><br>
(2.19) — <ins>a free pack (7.1.7).</ins>
</blockquote>
<p>5.1.1 [expr.prim.general] ¶8:</p>
<blockquote class="std">
<p class="grammarlhs">qualified-id:</p>
<p class="grammarrhs">nested-name-specifier <ins><tt>...</tt><sub>opt</sub></ins> <tt>template</tt><sub>opt</sub> unqualified-id</p>
<p class="grammarlhs">nested-name-specifier:</p>
<p class="grammarrhs">…</p>
<p class="grammarrhs">nested-name-specifier <ins><tt>...</tt><sub>opt</sub></ins> <tt>template</tt><sub>opt</sub> simple-template-id <tt>::</tt></p>
</blockquote>
<p>5.1.1 [expr.prim.general] ¶9:</p>
<blockquote class="std"><del>A</del> <ins>The result of a <em>qualified-id</em> whose</ins> <em>nested-name-specifier</em> <del>that</del> denotes a class,
<del>optionally followed by the keyword <tt>template</tt> (14.2), and then
followed by the</del> <ins>and whose <em>unqualified-id</em> is the</ins> name of a member of either that class (9.2) or one of its base classes (Clause 10), is <del>a
<em>qualified-id</em></del> <ins>that member</ins>; 3.4.3.1 describes name lookup for class members that appear in <em>qualified-id</em>s. <del>The result is the
member.</del></blockquote>
<p>(Note: this is due to the introduction of the ellipsis in the grammar production.)</p>
<p>5.1.2 [expr.prim.lambda] ¶3:</p>
<blockquote class="std">A <em>lambda-expression</em> shall not appear in an unevaluated operand (Clause 5), in a <em>template-argument</em>,
in an <em>alias-declaration</em>, in a <tt>typedef</tt> declaration, <del>or</del> in the declaration of a function or function
template outside its function body and default arguments<ins>, or in a <em>pack-declaration</em> (7.1.7)</ins>.</blockquote>
<p>5.2 [expr.post] ¶1:</p>
<blockquote class="std"><p class="grammarlhs">pseudo-destructor-name:</p>
<p class="grammarrhs">nested-name-specifier<sub>opt</sub> type-name <tt>:: ~</tt> type-name</p>
<p class="grammarrhs">nested-name-specifier <ins><tt>...</tt><sub>opt</sub></ins> <tt>template</tt> simple-template-id <tt>:: ~</tt> type-name</p>
<p class="grammarrhs">…</p></blockquote>
<!--
<p>5.2.5 [expr.ref] ¶4 :</p>
<blockquote class="std">(4.5) —  If <tt>E2</tt> is a member enumerator and the type of <tt>E2</tt> is <tt>T</tt>,<ins> or <tt>E2</tt> is a free value pack with element type <tt>T</tt>,</ins> the expression <tt>E1.E2</tt> is a prvalue. The type of
<tt>E1.E2</tt> is <tt>T</tt>.</blockquote>
-->
<p>7 [dcl.dcl] ¶1:</p>
<blockquote class="std">
<p class="grammarlhs">block-declaration:</p>
<p class="grammarrhs">…</p>
<p class="grammarrhs">opaque-enum-declaration</p>
<p class="grammarrhs"><ins>type-pack-declaration</ins></p>
</blockquote>
<p>7.1.6.2 [dcl.type.simple] ¶1:</p>
<blockquote class="std">
<p class="grammarlhs">simple-type-specifier:</p>
<p class="grammarrhs">nested-name-specifier<sub>opt</sub> type-name</p>
<p class="grammarrhs">nested-name-specifier <ins><tt>...</tt><sub>opt</sub></ins> <tt>template</tt> simple-template-id</p>
</blockquote>
<p>7.1.6.3 [dcl.type.elab] ¶1:</p>
<blockquote class="std">
<p class="grammarlhs">elaborated-type-specifier:</p>
<p class="grammarrhs">class-key attribute-specifier-seq<sub>opt</sub> nested-name-specifier<sub>opt</sub> identifier</p>
<p class="grammarrhs">class-key simple-template-id</p>
<p class="grammarrhs">class-key nested-name-specifier <ins><tt>...</tt><sub>opt</sub></ins> <tt>template</tt><sub>opt</sub> simple-template-id</p>
<p class="grammarrhs"><tt>enum</tt> nested-name-specifier<sub>opt</sub> identifier</p></blockquote>
<p>Introduce the section 7.1.7 [dcl.pack] "Pack specifiers":</p>
<blockquote class="stdins"><h4>7.1.7 Pack specifiers
<div style="text-align: right; float: right;">[dcl.pack]</div></h4>
<ol>
<li><p>A <em>pack-specifier</em> introduces a <em>pack-declaration</em>, which declares a <em>free pack</em>.
A <em>pack</em> is a free pack or a parameter pack. [<i>Note</i>: 14.5.3 handles parameter packs. Declarations of parameter packs are not <em>pack-declaration</em>s.
<i>— end note</i>]</p>
<p class="grammarrhs">pack-specifier:</p>
<p class="grammarrrhs">type-parameter-key</p>
<p class="grammarrrhs">type-id</p>
<p class="grammarrrhs"><tt>template < </tt>template-parameter-list<tt> > </tt>type-parameter-key</p><br>
<p class="grammarrhs">pack-declaration:</p>
<p class="grammarrrhs">pack-specifier <tt>...</tt> identifier attribute-specifier-seq<sub>opt</sub> <tt>=</tt><sub>opt</sub>
<tt>{</tt> template-argument-list <tt>} ;</tt></p>
<li><p>The <em>template-argument-list</em> has to satisfy the rules specified in 14.3 [temp.arg], where “<em>pack-specifier</em> <tt>...</tt>”
is a hypothetical template parameter pack and the elements of the <em>template-argument-list</em> the corresponding <em>template-argument</em>s.
If the <em>pack-specifier</em> is a type, any top-level <em>cv-qualifier</em>s are ignored.</p></li>
<li><p>A <em>pack-declaration</em> can be the <em>declaration</em> of a <em>template-declaration</em>. Such a template is called a pack template (see 14.5.8).</p></li>
<li><p>A <em>pack-declaration</em> can occur at block scope, at namespace scope, and at class scope.</p></li>
<li value="11"><p>If a pack expansion's pattern contains a <em>template-id</em> that names a specialization of a pack template,
its template arguments shall not be unexpanded packs. [ <em>Example:</em> </p>
<pre class="example"><code class="ins">typename... foo = {int, char, double};
template <typename T>
typename... baz = {T, T};
typename... x = {baz<foo>...}; // Error: Pattern contains baz<foo>, a pack template with a pack argument </code></pre>
</li>
</ol></blockquote>
<p>Drafting note: The intermediate paragraphs are to be filled with what is moved from 14.5.3 (see below).</p>
<p>14 [temp] ¶1:</p>
<blockquote class="std"><p>A template defines a family of classes or functions or an alias for a family of types<ins> or packs</ins>.</p>
<p class="grammarrhs">template-declaration:</p>
<p class="grammarrrhs"><tt>template < </tt> template-parameter-list <tt>></tt> declaration </p><br>
<p class="grammarrhs">template-parameter-list:</p>
<p class="grammarrrhs">template-parameter</p>
<p class="grammarrrhs">template-parameter-list <tt>,</tt> template-parameter</p>
<p>The <em>declaration</em> in a <em>template-declaration</em> shall</p>
<ul><li><p>…</p></li>
<li><p>be an <em>alias-declaration</em><del>.</del><ins>, or</ins></p></li>
<li><p><ins>be a <em>pack-declaration</em>.</ins></p></li></ul>
</blockquote>
<p>14.1 [temp.param] ¶15:</p>
<blockquote class="std">A template parameter pack that is a <em>parameter-declaration</em> whose type contains one or
more unexpanded <del>parameter</del> packs is a pack expansion. Similarly, a template parameter pack that is a
<em>type-parameter</em> with a <em>template-parameter-list</em> containing one or more unexpanded <del>parameter</del> packs is a pack
expansion. A template parameter pack that is a pack expansion shall not expand a parameter pack declared
in the same <em>template-parameter-list</em><ins>, and shall expand at least one free pack or parameter pack of an enclosing template.</ins>.
[ <em>Example:</em> <pre class="example"><code>[…]
<ins>typename... Ts {int, long};
template <typename T, typename T::... pack...> class A {}; // Error: Can only expand T::pack, which is dependent
template <typename T, typename T::... template templs<Ts>...> class A {}; // Ok: Expands fixed sized “Ts” </ins></code></pre> <em>— end example</em> ]
</blockquote>
<p>14.2 [temp.names] ¶4:</p>
<blockquote class="std">When the name of a member template specialization appears after <tt>.</tt> or <tt>-></tt> in a <em>postfix-expression</em> or after a
<em>nested-name-specifier</em> in a <em>qualified-id</em>, and the object expression of the <em>postfix-expression</em> is type-dependent
or the <em>nested-name-specifier</em> in the <em>qualified-id</em> refers to a dependent type, but the name is not a member of
the current instantiation (14.6.2.1), the member template name must be prefixed by the keyword <tt>template</tt>. Otherwise the name is assumed to name a non-template.</blockquote>
<p><b>Move 14.5.3 [temp.variadic] ¶4,5,6,7,8,9 to section 7.1.7 [dcl.pack] (starting at ¶5), making the following changes:</b></p>
<p>7.1.7 [dcl.pack] ¶6:</p>
<blockquote class="std">For the purpose of determining whether a <del>parameter</del> pack satisfies a rule regarding entities other than
<del>parameter</del> packs, the <del>parameter</del> pack is considered to be the entity that would result from an instantiation of
the pattern in which it appears.</blockquote>
<p>7.1.7 [dcl.pack] ¶7:</p>
<blockquote class="std">A <del>parameter</del> pack whose name appears within the pattern of a pack expansion is expanded by that pack
expansion. An appearance of the name of a <del>parameter</del> pack is only expanded by the innermost enclosing pack
expansion. The pattern of a pack expansion shall name one or more <del>parameter</del> packs that are not expanded
by a nested pack expansion; such <del>parameter</del> packs are called <em>unexpanded</em> <del>parameter</del> packs in the pattern. All
of the <del>parameter</del> packs expanded by a pack expansion shall have the same number of arguments specified.
An appearance of a name of a <del>parameter</del> pack that is not expanded is ill-formed.</blockquote>
<p>Introduce 7.1.7 [dcl.pack] ¶8 (8.3):</p>
<blockquote class="stdins"><p>(8.3) —   if the pack is a free pack,</p>
<div style="margin-left: 3.5em;"><ul>
<li>if the pack is of types, each element is a <em>type-id</em> representing the type designated by the corresponding <em>template-argument</em>, or</li>
<li>if the pack is of templates, each element is a <em>template-name</em> naming the template designated by the corresponding <em>template-argument</em>, or</li>
<li>if the pack is of values, each element is an <em>expression</em> whose type and value matches the <em>template-argument</em></li></ul></div></blockquote>
<p>7.1.7 [dcl.pack] ¶9:</p>
<blockquote class="std">The instantiation of a <tt>sizeof...</tt> expression (5.3.3) produces an integral constant containing the number of
elements in the <del>parameter</del> pack it expands.</blockquote>
<p>7.1.7 [dcl.pack] ¶10:</p>
<blockquote class="std">For a binary fold-expression, <tt>E</tt> is generated by instantiating the <em>cast-expression</em> that did not contain
an unexpanded <del>parameter</del> pack.</blockquote>
<p>Introduce the section 14.5.8 [temp.pack] "Pack templates" (essentially adapting 14.5.7 [temp.alias]):</p>
<blockquote class="stdins"><h4>14.5.8 Pack templates
<div style="text-align: right; float: right;">[temp.pack]</div></h4>
<ol>
<li><p>A <em>template-declaration</em> in which the <em>declaration</em> is an <em>pack-declaration</em> (7.1.7) declares the <em>identifier</em> to
be a <em>pack template</em>. A pack template is a name for a family of packs. The name of the pack template is a <em>template-name</em>.</p></li>
<li><p>When a <em>template-id</em> refers to the specialization of an pack template, is equivalent to the associated pack
obtained by substitution of its <em>template-argument</em>s for the <em>template-parameter</em>s in the <em>braced-init-list</em> of the pack
template. [ <em>Note</em>: An pack template name is never deduced. — <em>end note</em> ]</p></li>
<li><p>However, if the <em>template-id</em> is dependent, subsequent template argument substitution still applies to the <em>template-id</em>.
[<em>Example:</em></p> <pre class="example"><code class="ins">template <typename T> typename... pack = {};
template <typename T> void f(pack<typename T::foo>...);
f<int>(); // Error: int is not a class type</code></pre> <p><em>— end example</em>]</p></li>
<li><p>The <em>braced-init-list</em> in a pack template declaration shall not refer to the pack template being declared. The pack
produced by a pack template specialization shall not directly or indirectly make use of that specialization.</p></li>
</ol></blockquote>
<p>14.5 [temp.decls] ¶3:</p>
<blockquote class="std">Because <del>an</del> <em>alias-declaration</em><ins>s and <em>pack-declaration</em>s</ins> cannot declare a <em>template-id</em>,
it is not possible to partially or explicitly specialize an alias <ins>or pack</ins> template.</blockquote>
<p>14.6 [temp.res]:</p>
<blockquote class="std">
<ol><li value="2">A name used in a template declaration or definition and that is dependent on a <em>template-parameter</em> is assumed
not to name a type unless the applicable name lookup finds a type name or the name is qualified by the keyword <tt>typename</tt>. <ins>Such a name that denotes a pack
is not assumed to name a type pack unless the applicable name lookup finds the declaration of a type pack or the <em>unqualified-id</em> in the name is
qualified by an ellipsis.</ins>
</li>
<li value="3"><p>When a <em>qualified-id</em> is intended to refer to a type <ins>or free type pack</ins> that is not a member of the current instantiation (14.6.2.1)
and its <em>nested-name-specifier</em> refers to a dependent type, it shall be prefixed by the keyword <tt>typename</tt>, forming a <em>typename-specifier</em>.
If the <em>qualified-id</em> in a <em>typename-specifier</em> does not denote a type <ins>or free type pack</ins>, the program is ill-formed. […]</p></li>
<li value"4"><p>If a specialization of a template is instantiated for a set of <em>template-argument</em>s such that the <em>qualified-id</em>
prefixed by <tt>typename</tt> does not denote a type <ins>or free type pack</ins>, the specialization is ill-formed.</p></li>
<li value="6"><p>If, for a given set of template arguments, a specialization of a template is instantiated that refers to a
<em>qualified-id</em> that denotes a type<ins> or type pack</ins>, and the <em>qualified-id</em> refers to a member of an unknown specialization, the
<em>qualified-id</em> shall either be prefixed by <tt>typename</tt> or shall be used in a context in which it implicitly names a
type as described above. [<em>Example:</em> … <em>— end example</em>]<ins> [<em>Example:</em></ins>
<pre class="example"><code class="ins">template <class T> void f(int i) {
cout << ... << (i * T::x); // x shall not be a type
}
struct A {static int const x = 0;};
struct B {typename... x = {int};};
struct C {int... x = {1, 2, 3};};
f<A>(1); // Error: No unexpanded pack in “cout” and “(i * T::x)”
f<B>(1); // Error: x is a type pack
f<C>(1); // Ok: C::x is expanded</code></pre>
<ins><em>— end example</em>]</ins></p></li>
<li><p>Within the definition of a class template or within the definition of a member of a class template following
the <em>declarator-id</em>, the keyword <tt>typename</tt> is not required when referring to the name of a previously declared
member of the class template that declares a type<ins> or type pack</ins>.</p></li>
<li value="8"><p> (8.2) —   every valid specialization of <del>a variadic</del> template requires an empty template parameter pack<ins> or empty free pack</ins>,
or</p></li>
</ol>
</blockquote>
<h3>References</h3>
<p>[<a id="P0341">P0341</a>] “Packaging Parameter Packs (Rev. 2)“: <a href="http://wg21.link/p0341r0">wg21.link/p0341r0</a></p>
<p>[<a id="SO1">SO1</a>] “Can tuple variadic template recursion be improved with C++14 index sequences?“: <a href="http://stackoverflow.com/q/26365549/3647361">
stackoverflow.com/q/26365549/3647361</a><br>
[<a id="SO2">SO2</a>] “Compact and Simple std::tuple inversion“: <a href="http://stackoverflow.com/a/28240811/3647361">
stackoverflow.com/a/28240811/3647361</a><br>
[<a id="SO3">SO3</a>] “Check traits for all variadic template arguments“: <a href="
http://stackoverflow.com/a/28253503/3647361">
stackoverflow.com/a/28253503/3647361</a><br>
[<a id="SO4">SO4</a>] “How to implement a variadic tuple_map operation?“: <a href="
http://stackoverflow.com/a/26246990/3647361">
stackoverflow.com/a/26246990/3647361</a><br>
[<a id="SO4">SO5</a>] “Parameter pack, capture clause and initializers“: <a href="
http://stackoverflow.com/a/36939483/3647361">
stackoverflow.com/a/36939483/3647361</a></p>
<p>[<a id="COMP1">COMP1</a>] “Variadic Templates in C++0x need some additional features […]“:
<a href="https://groups.google.com/d/msg/comp.std.c++/_-6X_xZlKlA/-HhvKh5ccEAJ">
groups.google.com/d/msg/comp.std.c++/_-6X_xZlKlA/-HhvKh5ccEAJ</a></p>
<p>[<a id="CWG1520">CWG1520</a>] “Alias template specialization vs pack expansion“: <a href="http://wg21.link/cwg1520">wg21.link/cwg1520</a></p>
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.4.0/styles/idea.min.css">
<script src="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.4.0/highlight.min.js"></script>
<script>hljs.initHighlighting();</script>
</body>
</html>