-
Notifications
You must be signed in to change notification settings - Fork 0
/
D1069R0.html
419 lines (333 loc) · 22.1 KB
/
D1069R0.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
<!DOCTYPE html>
<html lang="en"><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<style>
.comment { color: #999999; font-style: italic; }
.pre { color: #000099; }
.string { color: #009900; }
.char { color: #009900; }
.float { color: #996600; }
.int { color: #999900; }
.bool { color: #000000; font-weight: bold; }
.type { color: #FF6633; }
.flow { color: #FF0000; }
.keyword { color: #990000; }
.operator { color: #663300; font-weight: bold; }
.operator { color: #663300; font-weight: bold; }
pre.code {
border: 2px solid #666;
background-color: #F4F4F4;
padding-left: 10px;
padding-top: 0px;
}
code {
border: 2px solid #d0d0d0;
background-color: LightYellow;
padding: 2px;
padding-left: 10px;
display:table;
white-space:pre;
margin:2px;
margin-bottom:10px;
}
dt {
font-weight: bold;
}
.ins {
background-color:#A0FFA0;
}
.del {
background-color:#FFA0A0;
text-decoration:line-through
}
.TODO {
background-color: LightYellow;
color: red;
}
</style>
<title>Refining standard library support for Class Template Argument Deduction</title>
</head>
<body>
<p>Document number: P1069R0 <br>
Date: 2018-10-08<br>
Reply-To:<br>
Mike Spertus, Symantec (<a href="mailto:mike_spertus@symantec.com">mike_spertus@symantec.com</a>)<br>
Walter E. Brown (<a href="mailto:webrown.cpp@gmail.com"> webrown.cpp@gmail.com</a>)<br>
Stephan T. Lavavej (<a href="mailto:stl@exchange.microsoft.com">stl@exchange.microsoft.com</a>)<br>
Audience: {Library Evolution, Library} Working Group
</p>
<h1>Refining standard library support for Class Template Argument Deduction</h1>
<h2>Introduction</h2>
<p> In this paper, we describe the changes to library support for class template argument deduction
that we believe are appropriate for C++20. <ul>
<li>Adding new
overloads to <tt>make_unique</tt> and <tt>make_shared</tt> to support an important
use case</li>
<li>(Re)adding some container constructors in support of P1021R1, which (if adopted) we
hope will provide a powerful use case for supporting deduction
from allocators that did not exist in C++17.</li>
<li>Finally, while we think the committee did an exceptional job on standard library
deduction guides in C++17 and there is very little that we would have changed
in retrospect except for one decision (the
handling of <tt>reference_wrapper</tt>s) that we feel should
be corrected. We present a rationale that we believe was not discussed at the time in
support of this</li></ul>
<h2>Overloading <tt>make_unique</tt> and <tt>make_shared</tt></h2>
While class template argument deduction can be used for
objects with static and automatic duration, it generally cannot be
used for creating objects with dynamic duration as the following attempts show:
<code>optional o(5); // OK. Static duration. optional<int>
// Try to create dynamic duration object.
auto o1 = new optional(5); // Already violates both Core Guidelines <a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rr-ptr">R.3</a> and <a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rr-newdelete">R.11</a><br>
<strike>auto o2 = unique_ptr(o1);</strike> // Oops, ill-formed. Can't deduce unique_ptr from raw ptr</code>
We propose simply making dynamic object creation with <tt>make_unique</tt> and <tt>make_shared</tt>
work just like the normal way one would translate a static and automatic declaration to a dynamic
declaration
<code>int i1(5); // Static
auto i2 = make_unique<int>(5); // Make dynamic by moving decl-specifier to make_unique template argument
option o1(5);
auto o2 = make_unique<optional>(5); // Again, make dynamic by moving decl-specifier to make_unique template argument</code>
Implementing this can be as simple as the following code, which can be seen working on <a href="https://wandbox.org/permlink/jn49SA7tlDO02gcw">Wandbox</a>
<code>template<template <typename ...U> typename T, typename ...A>
auto make_unique(A&& ...a) {
return std::unique_ptr<decltype(T(std::forward<A>(a)...))>(new T(std::forward<A>(a)...));
}</code>
<b>Notes:</b>
<ul><li>For simplicity, we do not propose supporting the case of non-type template parameters as
it is far less frequent and seems far more complex.
If and only if library implementers feel that there are no implementation concerns for non-type
template parameters, then that should be supported as well</li>
<li>It is worth pointing out that because this code exactly matches <em>mutatis mutandi</em> the automatic duration
declaration case, it should have no cause to be in any way more dangerous or confusing
that what is supported for objects created with static or automatic duration</li></ul>
<!-- <h2>Decay from arrays</h2>
As Nico Josuttis has pointed out, the following code throws a run-time error
instead of a compile-time error as expected (<a href="https://wandbox.org/permlink/jRLmw7StRIoJe7w5">wandbox</a>):
<code> vector v("foo", "bar");
for(auto x : v) {
cout << x;
}</code>
The surprising point is that the two character arrays decay to pointers and are therefore
interpreted as iterators into a <tt>vector<char></tt>. We propose simply specifying that
the containers should not succeed in deducing from two arrays where iterators are expected. -->
<h2>Allow containers to deduce from allocators or comparators</h2>
<b>Note:</b> This item has a dependency on <a href="http://wg21.link/p1021r1">P1021R1</a> as described
below.<p>A number of associative container guides were removed in the late stages of the Kona meeting
for the following reasons
<ul><li>Since the <tt>size_type</tt> member may or may not be a deduced context,
and different compilers handle “most specialized” differently when some candidates
are deducible and others are non-deducible for the same argument, there were implementability concerns.</li>
<li>Even where there were no implementability concerns,
construction from allocators was removed from all other containers for consistency with
associative containers.</li>
<li>A general agreement that trying to deduce the value type for a container from its
allocator was an anti-pattern</li>
<li>In addition, there were no constructors from comparators because the value type
could not be deduced from a comparator anyway.</li></ul>
<p>We propose restoring guides so that containers deduce consistently from all of their constructors
not because we disagree with any of the above, but because P1021R1's support
for partial specialization in class template argument deduction, if accepted, adds a very important
and useful new use case for them.
<code>vector<int> v{MyAlloc{}}; // Want vector<int, MyAlloc>
set<string> caseInsensitiveStrings([](string const &a, string const &b) { /* ... */ });</code>
Speaking “conceptually”, we also suggest that deducing correctly
from all constructors is valuable because the reason that STL containers need a lot of deduction guides in the first place is because they are not conceptized (See the bottom of <a href="http://qr.w69b.com/g/qE1JDD0Sk">http://qr.w69b.com/g/qE1JDD0Sk</a> for a demonstration
of some current deduction guides becoming unnecessary in a conceptized STL). If we ever have a concept-enabled STL, then the example in use case 1 above will work even without a deduction guide, so this is not only useful now but better prepares us for the future concepts vision.
<p>The new deduction guides are similar to the previously removed deduction guides with the
following changes, which incidentally greatly simplify their original versions:
<ul><li>To steer clear of the technical concern mention above, we simply use <tt>size_t</tt> in the following wording
(Note that using <tt>size_t</tt> does not assume that the container's <tt>size_type</tt> is <tt>size_t</tt>,
just that it is just an integral type being used for overload resolution).</li>
<li>We do not attempt to deduce the value type from the allocator. This is sufficient
for the new use cases and steers clear of the above concern</li>
<li>We also add deduction from comparators</li></ul>
<h2><tt>reference_wrapper</tt> and <tt>pair/tuple</tt> deduction</h2>
<p>In <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0433r0.html">P0433R0</a>, it was proposed that deduction guides for <tt>pair</tt> and <tt>tuple</tt> unwrap <tt>reference_wrapper</tt> like <tt>make_pair</tt> and <tt>make_tuple</tt> do. Such unwrapping was removed from later revisions of the paper and not adopted in C++17. According to both the minutes and the mailing list, unwrapping was suppressed in order to increase applicability to fully generic programming. However, as the following code available at <a href="https://wandbox.org/permlink/rRITtZ2gT2ZqR4jY">https://wandbox.org/permlink/rRITtZ2gT2ZqR4jY</a> shows, the possibility of picking up stray constructors suggests that fully generic programming should fully specialize template parameters anyway (note that this best practice is not limited to CTAD) rather than relying on <tt>tuple</tt> CTAD.</p>
<code>template<typename ...T> // CTAD: Intends tuple<T...> but stray constructors make unreliable
using ctad = decltype(tuple{declval<T>()...});
template<typename ...T> // Explicit: Produces tuple<T...> as intended
using expl = decltype(tuple<T...>{declval<T>()...});
int main()
{
print_type<ctad<tuple<lt;int>>>(); // std::tuple<int>
print_type<expl<tuple<int>>>(); // std::tuple<std::tuple<int>>
print_type<ctad<allocator_arg_t, allocator<int>, int>>(); // std::tuple<int>
print_type<expl<allocator_arg_t, allocator<int>, int>>(); // std::tuple<std::allocator_arg_t, std::allocator<int>, int>
return 0;
}
</code>
<p>However, with the C++17 behavior, not only does <tt>pair/tuple</tt> deduction not support generic metaprogramming, its inability to deduce references limits its ability to replace <tt>make_tuple</tt> or <tt>make_pair</tt> even though many expositions (E.g., [<a href="https://arne-mertz.de/2017/06/class-template-argument-deduction/">1</a>], [<a href="https://blog.tartanllama.xyz/deduction-for-class-templates/">2</a>], and [<a href="https://tech.io/playgrounds/2205/7-features-of-c17-that-will-simplify-your-code/template-argument-deduction-for-class-templates">3</a>]) give <tt>make_pair</tt> replacement as their motivating use case. As library vocabulary vocabulary types whose pre-CTAD factory functions unwrap <tt>reference_wrapper</tt>, we suggest that behavior preserved in CTAD.</p>
<h3>Wording</h3>
In addition to the below, change all of the “<em>see below</em>::size_type”
with <tt>size_t</tt> in deduction guides, simplifying and increasing robustness<p>
Add the following deduction guide to the definition of class <tt>basic_string</tt> in
§24.3.2 [basic.string]:
</p><blockquote><pre> int compare(size_type pos1, size_type n1,
const charT* s, size_type n2) const;
};
<span class="ins">template<class T, class Traits = char_traits<T>, class Allocator>
basic_string(Allocator) -> basic_string<T, Traits, Allocator>;
</span></pre></blockquote>
In §24.3.2.2 [string.cons], insert the following:
<blockquote><pre><span class="ins">template<class T, class Traits = char_traits<T>, class Allocator>
basic_string(Allocator) -> basic_string<T, Traits, Allocator>;
</span></pre>
<blockquote><span class="ins"><em>Remarks:</em> Shall not participate in overload resolution if <tt>Allocator</tt> is a type that does not qualify as an allocator [sequence.reqmts].</span></blockquote></blockquote>
At the end of the definition of class <tt>deque</tt> in §26.3.8.1 [deque.overview], add
the following deduction guides:
<blockquote><pre> void clear() noexcept;
};
<span class="ins">template<class T, class Allocator>
explicit deque(Allocator) -> deque<T, Allocator>;
template<class T, class Allocator> explicit deque(size_t, Allocator) -> deque<T, Allocator>;</span></pre></blockquote>
At the end of the definition of class <tt>forward_list</tt> in §26.3.9.1 [forwardlist.overview],
add the following deduction guides:
<blockquote><pre> void reverse() noexcept;
};
<span class="ins"> template<class T, class Allocator>
explicit forward_list(Allocator) -> forward_list<T, Allocator>;
template<class T, class Allocator>
explicit forward_list(size_t, Allocator) -> forward_list<T, Allocator>;</span></pre></blockquote>
At the end of the definition of class <tt>list</tt> in §26.3.10.1 [list.overview],
add the following deduction guides:
<blockquote><pre> void reverse() noexcept;
};
<span class="ins"> template<class T, class Allocator>
explicit list(Allocator) -> list<T, Allocator>;
template<class T, class Allocator>
explicit list(size_t, Allocator) -> list<T, Allocator>;</span></pre></blockquote>
At the end of the definition of class <tt>vector</tt> in §26.3.11.1 [vector.overview],
add the following <em>deduction-guide</em>:
<blockquote><pre> void clear() noexcept;
};
<span class="ins"> template<class T, class Allocator>
explicit vector(Allocator) -> vector<T, Allocator>;
template<class T, class Allocator>
explicit vector(size_t, Allocator)
-> vector<T, Allocator>;</span></pre></blockquote>
At the end of the definition of class <tt>map</tt> in §26.4.4.1 [map.overview],
add the following deduction guides:
<blockquote><pre> pair<const_iterator, const_iterator> equal_range(const K& x) const;
};
<span class="ins"> template<class Key, class T, class Compare, class Allocator = allocator<pair<Key, T>>>
explicit map(Compare, Allocator = Allocator())
-> map<Key, T, Compare, Allocator>;</span>
<span class="ins"> template<class Key, class T, class Compare = less<Key>, class Allocator>
explicit map(Allocator)
-> map<Key, T, Compare, Allocator>;</span></pre></blockquote>
At the end of the definition of class <tt>multimap</tt> in §26.4.5.1 [multimap.overview],
add the following deduction guides:
<blockquote><pre> pair<const_iterator, const_iterator> equal_range(const K& x) const;
};
<span class="ins"> template<class Key, class T, class Compare, class Allocator = allocator<pair<Key, T>>>
explicit multimap(Compare, Allocator = Allocator())
-> multimap<Key, T, Compare, Allocator>;</span>
<span class="ins"> template<class Key, class T, class Compare = less<Key>, class Allocator>
explicit multimap(Allocator)
-> multimap<Key, T, Compare, Allocator>;</span></pre></blockquote>
At the end of the definition of class <tt>set</tt> in §26.4.6.1 [set.overview],
add the following <em>deduction-guide</em>s:
<blockquote><pre> template <class K>
pair<const_iterator, const_iterator> equal_range(const K& x) const;
};
<span class="ins"> template<class T, class Compare, class Allocator>
explicit set(Compare, Allocator = allocator<T>)
-> set<T, Compare, Allocator>;</span>
<span class="ins"> template<class T, class Compare = less<T>, class Allocator>
explicit set(Allocator)
-> set<T, Compare, Allocator>;</span></pre></blockquote>
At the end of the definition of class <tt>multiset</tt> in §27.4.6.1 [multiset.overview],
add the following deduction guides:
<blockquote><pre> template <class K>
pair<const_iterator, const_iterator> equal_range(const K& x) const;
};
<span class="ins"> template<class T, class Compare, class Allocator>
explicit multiset(Compare, Allocator = allocator<T>)
-> multiset<T, Compare, Allocator>;</span>
<span class="ins"> template<class T, class Compare = less<T>, class Allocator>
explicit multiset(Allocator)
-> multiset<T, Compare, Allocator>;</span></pre></blockquote>
Modify §26.5.4.1 [unord.map.overview],
add the following <em>deduction-guide</em>s:
<blockquote><pre> void reserve(size_type n);
};
<span class="ins"> template<class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>, class Allocator>
explicit unordered_map(size_t, Hash, Pred = Pred(), Allocator = Allocator())
-> unordered_map<Key, T, Hash, Pred, Allocator>;</span>
<span class="ins"> template<class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>, class Allocator>
explicit unordered_map(Allocator)
-> unordered_map<Key, T, Hash, Pred, Allocator>;</span>
<span class="ins"> template<class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>, class Allocator>
explicit unordered_map(size_t, Allocator)
-> unordered_map<Key, T, Hash, Pred, Allocator>;
template<class Key, class T, class Hash, class Pred = equal_to<Key>, class Allocator>
explicit unordered_map(size_t, Hash, Allocator)
-> unordered_map<Key, T,
Hash, Pred, Allocator>;</span></pre></blockquote>
Delete §26.5.4.1p4 [unord.map.overview]:
<blockquote><span class="del">A <tt>size_type</tt> parameter type in an <tt>unordered_map</tt> deduction
guide refers to the <tt>size_type</tt> member type of the type deduced by the deduction guide.</span></blockquote>
Modify §26.5.5.1 [unord.multimap.overview],
add the following <em>deduction-guide</em>s:
<blockquote><pre> void reserve(size_type n);
};
<span class="ins"> template<class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>, class Allocator>
explicit unordered_multimap(size_t, Hash, Pred = Pred(), Allocator = Allocator())
-> unordered_multimap<Key, T, Hash, Pred, Allocator>;</span>
<span class="ins"> template<class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>, class Allocator>
explicit unordered_multimap(Allocator)
-> unordered_multimap<Key, T, Hash, Pred, Allocator>;</span>
<span class="ins"> template<class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>, class Allocator>
explicit unordered_multimap(size_t, Allocator)
-> unordered_multimap<Key, T, Hash, Pred, Allocator>;
template<class Key, class T, class Hash, class Pred = equal_to<Key>, class Allocator>
explicit unordered_multimap(size_t, Hash, Allocator)
-> unordered_multimap<Key, T,
Hash, Pred, Allocator>;</span></pre></blockquote>
Delete §26.5.5.1p4 [unord.multimap.overview]:
<blockquote><span class="del">A <tt>size_type</tt> parameter type in an <tt>unordered_multimap</tt> deduction
guide refers to the <tt>size_type</tt> member type of the type deduced by the deduction guide.</span></blockquote>
Modify §26.5.6.1 [unord.set.overview] as follows:
<blockquote><pre> void reserve(size_type n);
};
<span class="ins"> template<class T, class Hash, class Pred = equal_to<T>, class Allocator = allocator<T>>
explicit unordered_set(size_t, Hash, Pred = Pred(), Allocator = Allocator())
-> unordered_set<T, Hash, Pred, Allocator>;</span>
<span class="ins"> template<class T, class Hash = hash<T>, Pred = equal_to<T>, class Allocator>
explicit unordered_set(size_t, Allocator)
-> unordered_set<T, Hash, Pred, Allocator>;
template<class T, class Hash, Pred = equal_to<T>, class Allocator>
explicit unordered_set(size_t, Hash, Allocator)
-> unordered_set<T, Hash, Pred, Allocator>;</span>
</pre></blockquote>
Delete §26.5.6.1p4 [unord.set.overview]:
<blockquote><span class="del">A <tt>size_type</tt> parameter type in an <tt>unordered_set</tt> deduction
guide refers to the <tt>size_type</tt> member type of the primary <tt>unordered_set</tt> template.</span></blockquote>
Modify §26.5.7.1 [unord.multiset.overview] as follows:
<blockquote><pre> void reserve(size_type n);
};
<span class="ins"> template<class T, class Hash, class Pred = equal_to<T>, class Allocator = allocator<T>>
explicit unordered_multiset(size_t, Hash, Pred = Pred(), Allocator = Allocator())
-> unordered_multiset<T, Hash, Pred, Allocator>;</span>
<span class="ins"> template<class T, class Hash = hash<T>, Pred = equal_to<T>, class Allocator>
explicit unordered_multiset(size_t, Allocator)
-> unordered_multiset<T, Hash, Pred, Allocator>;
template<class T, class Hash, Pred = equal_to<T>, class Allocator>
explicit unordered_multiset(size_t, Hash, Allocator)
-> unordered_multiset<T, Hash, Pred, Allocator>;</span>
</pre></blockquote>
Delete §26.5.7.1p4 [unord.multiset.overview]:
<blockquote><span class="del">A <tt>size_type</tt> parameter type in an <tt>unordered_multiset</tt> deduction
guide refers to the <tt>size_type</tt> member type of the primary <tt>unordered_multiset</tt> template.</span></blockquote>
At the end of the
definition of class <tt>promise</tt> in §33.6.6 [futures.promise], insert the following:
<blockquote><pre> <span class="comment">// setting the result with deferred notification</span>
void set_value_at_thread_exit(<em>see below</em>);
void set_exception_at_thread_exit(exception_ptr p);
};
<span class="ins"> template <class T, class Alloc> promise(allocator_arg_t, Alloc)
-> promise<T>;</span>
template <class R>
void swap(promise<R>& x, promise<R>& y) noexcept;
</pre></blockquote>
</body></html>