-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathUsingDeclarationPacks.html
208 lines (170 loc) · 8.62 KB
/
UsingDeclarationPacks.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
<html>
<style type="text/css">
<style type="text/css">
body { color: #000000; background-color: #FFFFFF; }
del { text-decoration: line-through; color: #8B0040; }
ins { text-decoration: underline; color: #005100; }
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: #F5F6A2;
border: 1px solid #E1E28E; }
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; }
blockquote.stddel { text-decoration: line-through;
color: #000000; background-color: #FFEBFF;
border: 1px solid #ECD7EC;
padding-left: 0.5empadding-right: 0.5em; ; }
blockquote.stdins { text-decoration: underline;
color: #000000; background-color: #C8FFC8;
border: 1px solid #B3EBB3; padding: 0.5em; }
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; }
</style>
</style>
<div style="text-align: right; float: right">
<p>ISO/IEC JTC1 SC22 WG21, Core Working Group<br>P0195R1<br>Robert Haberlach (rh633{at}cam{dot}ac.uk)<br>2016-10-</p>
</div>
<h2>Modernizing using-declarations</h2>
<p><em>using-declaration</em>s should be able to cope with lists and pack expansions to allow flexible injection of names.</p>
<h3>Motivation</h3>
<p>With variadic templates having been introduced in C++11, many language constructs were updated to operate on pack expansions.
Just as some situations require derivation from a pack of classes, some require introduction of a name from a pack of classes. Consider</p>
<pre class="extract">
template <typename... T>
struct Overloader : /* […] */ {
// […]
};
template <typename... T>
constexpr auto make_overloader(T&&... t) {
return Overloader<T...>{std::forward<T>(t)...};
}
int main() {
auto o = make_overloader([] (auto const& a) {std::cout << a;},
[] (float f) {std::cout << std::setprecision(3) << f;});
}
</pre>
<p>The implementation of <tt>Overloader</tt> is verbose and inefficient; One has to recursively introduce overloads of <tt>operator()</tt>:</p>
<pre class="extract">
template <typename T, typename... Ts>
struct Overloader : T, Overloader<Ts...> {
using T::operator();
using Overloader<Ts...>::operator();
// […]
};
template <typename T> struct Overloader<T> : T {
using T::operator();
};
</pre>
<p>While it's possible to achieve logarithmic instantiation depth, the resulting implementation
is needlessly complicated and still less efficient than the following, terse syntax:</p>
<pre class="extract">
template <typename... Ts>
struct Overloader : Ts... {
using Ts::operator()...;
// […]
};
</pre>
<h3>Design decisions and impact</h3>
<p>We propose that a <em>using-declaration</em> consist of a list of names, each called a <em>using-declarator</em>.
As the proposed change is solely an enhancement, well-formed programs and their semantics are unaffected.</p>
<h3>Proposed wording</h3>
<p>Modify 3.3.2 [basic.scope.pdecl] ¶4 as indicated:</p>
<blockquote class="std">The point of declaration of a <em>using-<del>declaration</del><ins>declarator</ins></em> that does not name a constructor is immediately after the
<em>using-<del>declaration</del><ins>declarator</ins></em> (7.3.3).</blockquote>
<p>Modify 3.4.3.1 [class.qual] ¶2 (2.2) as indicated:</p>
<blockquote class="std">— in <ins>a <em>using-declarator</em> of </ins>a <em>using-declaration</em> (7.3.3) that is a <em>member-declaration</em>, if the name specified after the <em>nested-name-specifier</em>
is the same as the <em>identifier</em> or the <em>simple-template-id</em>’s <em>template-name</em> in the last component of the <em>nested-name-specifier</em>,</blockquote>
<p>Modify 7.3.3 [namespace.udecl] ¶1 as indicated:</p>
<blockquote class="std"><del>A <em>using-declaration</em> introduces a
set of declarations into the declarative region in which the
<em>using-declaration</em> appears.</del>
<pre> <em>using-declaration</em>:
<del>typename<sub><em>opt</em></sub> <em>nested-name-specifier unqualified-id</em></del>
<ins>using <em>using-declarator-list</em>;</ins>
<ins><em>using-declarator-list:</em></ins>
<ins><em>using-declarator</em>...<sub><em>opt</em></sub></ins>
<ins><em>using-declarator-list</em>, <em>using-declarator</em>...<sub><em>opt</em></sub></ins>
<ins><em>using-declarator:</em></ins>
<ins>typename<sub><em>opt</em></sub> <em>nested-name-specifier unqualified-id</em></ins>
</pre>
<p><ins>Each <em>using-declarator</em> in a
<em>using-declaration</em><sup>98</sup> introduces a set of declarations
into the declarative region in which the <em>using-declaration</em>
appears.</ins>
The set of declarations introduced by the <em>using-<del>declaration</del><ins>declarator</ins></em>
is found by performing qualified name lookup
(3.4.3, 10.2) for the name in the <em>using-<del>declaration</del><ins>declarator</ins></em>,
excluding functions that are hidden as described
below. If the <em>using-<del>declaration</del><ins>declarator</ins></em>
does not name a constructor, the <em>unqualified-id</em> is declared in the
declarative region in which the <em>using-declaration</em> appears as a synonym for
each declaration introduced by the <em>using-<del>declaration</del><ins>declarator</ins></em>.
[ <em>Note</em>: Only the specified name is so declared; specifying an
enumeration name in a <em>using-declaration</em>
does not declare its enumerators in the
<em>using-declaration</em>’s declarative region.
— <em>end note</em> ]
If <del>the</del><ins>a</ins> <em>using-<del>declaration</del><ins>declarator</ins></em>
names a constructor, it declares that the class inherits the set of
constructor declarations introduced by the <em>using-declaration</em>
from the nominated base class.
<hr>
<ins><sup>98) A <em>using-declaration</em> with more than one <em>using-declarator</em> is equivalent to a corresponding sequence of
<em>using-declaration</em>s with one <em>using-declarator</em>.
</sup></ins>
</blockquote>
<p>Modify 7.3.3 [namespace.udecl] ¶3 as indicated:</p>
<blockquote class="std">
In a <em>using-declaration</em> used as a <em>member-declaration</em>, <del>the</del><ins>each <em>using-declarator</em>’s</ins> <em>nested-name-specifier</em> shall name a
base class of the class being defined. If <del>such</del> a <em>using-<del>declaration</del><ins>declarator</ins></em> names a constructor,
<del>the</del><ins>its</ins> <em>nested-name-specifier</em> shall name a direct base class of the class being defined. <ins>[ <em>Example:</em>
<pre class="example">
template <typename... bases>
struct X : bases... {
using bases::g...;
};
X<B, D> x; // OK: B::g and D::g introduced
</pre> — <em>end example</em> ]</ins>
</blockquote>
<p>Modify 7.3.3 [namespace.udecl] ¶10 as indicated:</p>
<blockquote class="std">
[<em>Example:</em>
<pre class="example">
namespace A {
int i;
}
namespace A1 {
<del>using A::i;</del>
using A::i<ins>, A::i</ins>; // OK: double declaration
}
struct B {
int i;
};
struct X : B {
<del>using B::i;</del>
using B::i<ins>, B::i</ins>; // error: double member declaration
};
</pre>
<em>— end example</em> ]
</blockquote>
<p>Modify 7.3.3 [namespace.udecl] ¶19 as indicated:</p>
<blockquote class="std">If a <em>using-<del>declaration</del><ins>declarator</ins></em> uses the keyword <tt>typename</tt> and specifies a dependent name (14.6.2),
the name introduced by the <em>using-declaration</em> is treated as a <em>typedef-name</em> (7.1.3).</blockquote>
<p>Add a bullet (4.13) the list in 14.5.3 [temp.variadic] ¶4:</p>
<blockquote class="stdins">— In a <em>using-declaration</em> (7.3.3); the pattern is a <em>using-declarator</em>. </blockquote>
<h3>Acknowledgments</h3>
<p>Thanks to Daveed Vandevoorde for assistance in preparing the wording.</p>
</html>