-
Notifications
You must be signed in to change notification settings - Fork 0
/
P1167R0.html
247 lines (241 loc) · 32.8 KB
/
P1167R0.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
<!DOCTYPE html>
<html><head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<link href="http://alexgorbatchev.com/pub/sh/current/styles/shThemeDefault.css" rel="stylesheet" type="text/css">
<link rel="stylesheet" type="text/css" href="https://cdn.rawgit.com/google/code-prettify/master/loader/prettify.css">
<script src="http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js" type="text/javascript"></script>
<!--<script src="http://alexgorbatchev.com/pub/sh/current/scripts/shAutoloader.js" type="text/javascript"></script>-->
<script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCpp.js" type="text/javascript"></script>
<style>
/**
* SyntaxHighlighter
* http://alexgorbatchev.com/SyntaxHighlighter
*
* SyntaxHighlighter is donationware. If you are using it, please donate.
* http://alexgorbatchev.com/SyntaxHighlighter/donate.html
*
* @version
* 3.0.83 (July 02 2010)
*
* @copyright
* Copyright (C) 2004-2010 Alex Gorbatchev.
*
* @license
* Dual licensed under the MIT and GPL licenses.
*/
.syntaxhighlighter {
background-color: white !important;
}
.syntaxhighlighter .line.alt1 {
background-color: white !important;
}
.syntaxhighlighter .line.alt2 {
background-color: white !important;
}
.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 {
background-color: #e0e0e0 !important;
}
.syntaxhighlighter .line.highlighted.number {
color: black !important;
}
.syntaxhighlighter table caption {
color: black !important;
}
.syntaxhighlighter .gutter {
color: #afafaf !important;
}
.syntaxhighlighter .gutter .line {
border-right: 3px solid #6ce26c !important;
}
.syntaxhighlighter .gutter .line.highlighted {
background-color: #6ce26c !important;
color: white !important;
}
.syntaxhighlighter.printing .line .content {
border: none !important;
}
.syntaxhighlighter.collapsed {
overflow: visible !important;
}
.syntaxhighlighter.collapsed .toolbar {
color: blue !important;
background: white !important;
border: 1px solid #6ce26c !important;
}
.syntaxhighlighter.collapsed .toolbar a {
color: blue !important;
}
.syntaxhighlighter.collapsed .toolbar a:hover {
color: red !important;
}
.syntaxhighlighter .toolbar {
color: white !important;
background: #6ce26c !important;
border: none !important;
}
.syntaxhighlighter .toolbar a {
color: white !important;
}
.syntaxhighlighter .toolbar a:hover {
color: black !important;
}
.syntaxhighlighter .plain, .syntaxhighlighter .plain a {
color: black !important;
}
.syntaxhighlighter .comments, .syntaxhighlighter .comments a {
color: #008200 !important;
}
.syntaxhighlighter .string, .syntaxhighlighter .string a {
color: blue !important;
}
.syntaxhighlighter .keyword {
color: #006699 !important;
}
.syntaxhighlighter .preprocessor {
color: gray !important;
}
.syntaxhighlighter .variable {
color: #aa7700 !important;
}
.syntaxhighlighter .value {
color: #009900 !important;
}
.syntaxhighlighter .functions {
color: #ff1493 !important;
}
.syntaxhighlighter .constants {
color: #0066cc !important;
}
.syntaxhighlighter .script {
font-weight: bold !important;
color: #006699 !important;
background-color: none !important;
}
.syntaxhighlighter .color1, .syntaxhighlighter .color1 a {
color: gray !important;
}
.syntaxhighlighter .color2, .syntaxhighlighter .color2 a {
color: #ff1493 !important;
}
.syntaxhighlighter .color3, .syntaxhighlighter .color3 a {
color: red !important;
}
.syntaxhighlighter .keyword {
font-weight: bold !important;
}
.syntaxhighlighter div.toolbar span a.toolbar_item{
display: none !important;
}
body .syntaxhighlighter .line {
white-space: pre !important;
}
.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.clo,.opn,.pun{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.kwd,.tag,.typ{font-weight:700}.str{color:#060}.kwd{color:#006}.com{color:#600;font-style:italic}.typ{color:#404}.lit{color:#044}.clo,.opn,.pun{color:#440}.tag{color:#006}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee}
</style>
<title>Improving function templates with Class Template Argument Deduction</title>
</head>
<body>
<p>D1167R0<br>
Mike Spertus, Symantec<br>
<a href="mailto:[email protected]">[email protected]</a><br>
2018-10-08<br>
Audience: Evolution Working Group
</p>
<h1>Improving function templates with Class Template Argument Deduction</h1>
This paper proposes
<ul><li>Allowing Function Templates to consider Class Template Argument Deduction
during Function Template Argument Deduction.</li>
<li>Allowing deduction guides for Function Templates</li>
</ul>
This greatly improves Function Template
Argument Deduction in important use cases as the following examples, which
will be discussed in more detail below, illustrate:
<table border="1"><tbody><tr><th>C++17</th><th>Proposed</th></tr>
<tr><td>
<div><div id="highlighter_722674" class="syntaxhighlighter nogutter cpp"><div class="toolbar"><span><a href="#" class="toolbar_item command_help help">?</a></span></div><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="cpp comments">// Example 1: “Output” version of std::quoted</code></div><div class="line number2 index1 alt1"><code class="cpp comments">// Needs many overloads since no CTAD for function template arguments</code></div><div class="line number3 index2 alt2"><code class="cpp keyword bold">template</code><code class="cpp plain"><</code><code class="cpp keyword bold">class</code> <code class="cpp plain">charT></code></div><div class="line number4 index3 alt1"><code class="cpp plain">T11 quoted(</code><code class="cpp keyword bold">const</code> <code class="cpp plain">charT* s, charT delim = charT(</code><code class="cpp string">'"'</code><code class="cpp plain">), charT escape = charT(</code><code class="cpp string">'\\'</code><code class="cpp plain">));</code></div><div class="line number5 index4 alt2"><code class="cpp spaces"> </code> </div><div class="line number6 index5 alt1"><code class="cpp keyword bold">template</code><code class="cpp plain"><</code><code class="cpp keyword bold">class</code> <code class="cpp plain">charT, </code><code class="cpp keyword bold">class</code> <code class="cpp plain">traits, </code><code class="cpp keyword bold">class</code> <code class="cpp plain">Allocator></code></div><div class="line number7 index6 alt2"><code class="cpp plain">T12 quoted(</code><code class="cpp keyword bold">const</code> <code class="cpp plain">basic_string<charT, traits, Allocator>& s,</code></div><div class="line number8 index7 alt1"><code class="cpp spaces"> </code><code class="cpp plain">charT delim = charT(</code><code class="cpp string">'"'</code><code class="cpp plain">), charT escape = charT(</code><code class="cpp string">'\\'</code><code class="cpp plain">));</code></div><div class="line number9 index8 alt2"><code class="cpp spaces"> </code> </div><div class="line number10 index9 alt1"><code class="cpp keyword bold">template</code><code class="cpp plain"><</code><code class="cpp keyword bold">class</code> <code class="cpp plain">charT, </code><code class="cpp keyword bold">class</code> <code class="cpp plain">traits, </code><code class="cpp keyword bold">class</code> <code class="cpp plain">Allocator></code></div><div class="line number11 index10 alt2"><code class="cpp plain">T14 quoted(basic_string_view<charT, traits, Allocator>& s,</code></div><div class="line number12 index11 alt1"><code class="cpp spaces"> </code><code class="cpp plain">charT delim = charT(</code><code class="cpp string">'"'</code><code class="cpp plain">), charT escape = charT(</code><code class="cpp string">'\\'</code><code class="cpp plain">));</code></div></div></td></tr></tbody></table></div></div></td>
<td valign="top"><div><div id="highlighter_18248" class="syntaxhighlighter nogutter cpp"><div class="toolbar"><span><a href="#" class="toolbar_item command_help help">?</a></span></div><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="cpp comments">// Example 1: Allow CTAD to deduce function template arguments</code></div><div class="line number2 index1 alt1"><code class="cpp keyword bold">template</code><code class="cpp plain"><</code><code class="cpp keyword bold">class</code> <code class="cpp plain">charT, </code><code class="cpp keyword bold">class</code> <code class="cpp plain">traits, </code><code class="cpp keyword bold">class</code> <code class="cpp plain">Allocator></code></div><div class="line number3 index2 alt2"><code class="cpp plain">T1 quoted(basic_string_view<charT, traits, Allocator>& s,</code></div><div class="line number4 index3 alt1"><code class="cpp spaces"> </code><code class="cpp plain">charT delim = charT(</code><code class="cpp string">'"'</code><code class="cpp plain">), charT escape = charT(</code><code class="cpp string">'\\'</code><code class="cpp plain">));</code></div></div></td></tr></tbody></table></div></div></td>
</tr>
<tr><td><div><div id="highlighter_615473" class="syntaxhighlighter nogutter cpp"><div class="toolbar"><span><a href="#" class="toolbar_item command_help help">?</a></span></div><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="cpp comments">// Example 2: Passing 'In' parameter by value or const & by efficiency</code></div><div class="line number2 index1 alt1"><code class="cpp keyword bold">template</code> <code class="cpp plain"><</code><code class="cpp keyword bold">typename</code> <code class="cpp plain">T> </code><code class="cpp keyword bold">void</code> <code class="cpp plain">do_f(T t); </code><code class="cpp comments">// Implements f</code></div><div class="line number3 index2 alt2"> </div><div class="line number4 index3 alt1"><code class="cpp keyword bold">template</code> <code class="cpp plain"><</code><code class="cpp keyword bold">typename</code> <code class="cpp plain">T> </code><code class="cpp keyword bold">inline</code> <code class="cpp keyword bold">void</code> <code class="cpp plain">f(T && t)</code></div><div class="line number5 index4 alt2"><code class="cpp plain">{</code></div><div class="line number6 index5 alt1"><code class="cpp spaces"> </code><code class="cpp plain">do_f<</code><code class="cpp keyword bold">typename</code> <code class="cpp plain">boost::call_traits<decay_t<T>>::type>(t);</code></div><div class="line number7 index6 alt2"><code class="cpp plain">}</code></div><div class="line number8 index7 alt1"> </div><div class="line number9 index8 alt2"><code class="cpp plain">f(7); </code><code class="cpp comments">// Pass by-value</code></div><div class="line number10 index9 alt1"><code class="cpp plain">f(vector {1, 2, 3, 4}); </code><code class="cpp comments">// Passed by const &</code></div></div></td></tr></tbody></table></div></div></td>
<td valign="top"><div><div id="highlighter_802777" class="syntaxhighlighter nogutter cpp"><div class="toolbar"><span><a href="#" class="toolbar_item command_help help">?</a></span></div><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="cpp comments">// Example 2: Allow Deduction Guides for Function Templates</code></div><div class="line number2 index1 alt1"><code class="cpp keyword bold">template</code> <code class="cpp plain"><</code><code class="cpp keyword bold">typename</code> <code class="cpp plain">T> </code><code class="cpp keyword bold">void</code> <code class="cpp plain">f(T t); </code><code class="cpp comments">// Implement here. No need to delegate</code></div><div class="line number3 index2 alt2"><code class="cpp keyword bold">template</code> <code class="cpp plain"><</code><code class="cpp keyword bold">typename</code> <code class="cpp plain">T> f(T t) -> f<</code><code class="cpp keyword bold">typename</code> <code class="cpp plain">boost::call_traits<T>::type>;</code></div><div class="line number4 index3 alt1"> </div><div class="line number5 index4 alt2"><code class="cpp plain">f(7); </code><code class="cpp comments">// Pass by-value</code></div><div class="line number6 index5 alt1"><code class="cpp plain">f(vector {1, 2, 3, 4}); </code><code class="cpp comments">// Passed by const &</code></div></div></td></tr></tbody></table></div></div></td></tr>
</tbody></table>
<h2>Argument deduction for function templates</h2>
A signature feature of C++ that has greatly contributed to the success of
the standard template library is that function templates generally deduce
their template arguments, so algorithms can usually
be called for any valid arguments and Function Template Argument Deduction
chooses the right specialization. However, Function Template Argument
Deduction fails to make many “expected” deductions because
it does not consider Class Template Argument Deduction like other declarations do, as we now propose:
<table border="1"><tbody><tr><td colspan="2">
<div><div id="highlighter_20539" class="syntaxhighlighter nogutter cpp"><div class="toolbar"><span><a href="#" class="toolbar_item command_help help">?</a></span></div><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="cpp comments">// Point class template along the lines of P0267R8</code></div><div class="line number2 index1 alt1"><code class="cpp keyword bold">template</code><code class="cpp plain"><</code><code class="cpp keyword bold">class</code> <code class="cpp plain">T> Point { T x; T y; };</code></div></div></td></tr></tbody></table></div></div></td></tr>
<tr><th>C++17</th><th>Proposed</th></tr>
<tr><td><div><div id="highlighter_874634" class="syntaxhighlighter nogutter cpp"><div class="toolbar"><span><a href="#" class="toolbar_item command_help help">?</a></span></div><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="cpp comments">// Function Template Argument Deduction fails</code></div><div class="line number2 index1 alt1"><code class="cpp plain">distance<</code><code class="cpp color1 bold">double</code><code class="cpp plain">>({0.0, 0.0}, {3.0, 4.0});</code></div></div></td></tr></tbody></table></div></div></td>
<td><div><div id="highlighter_850508" class="syntaxhighlighter nogutter cpp"><div class="toolbar"><span><a href="#" class="toolbar_item command_help help">?</a></span></div><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="cpp comments">// Fix by deducing argument from initializer</code></div><div class="line number2 index1 alt1"><code class="cpp plain">distance({0.0, 0.0}, {3.0, 4.0});</code></div></div></td></tr></tbody></table></div></div></td>
</tr></tbody></table>
Indeed, the standard library goes to great lengths to work around this by
add many function template overloads that merely duplicate Class Template Argument Deduction.
Consider the “Output” version of <tt>std::quoted</tt>:
<table border="1"><tbody><tr><th>C++17</th><th>Proposed</th></tr>
<tr><td>
<div><div id="highlighter_390278" class="syntaxhighlighter nogutter cpp"><div class="toolbar"><span><a href="#" class="toolbar_item command_help help">?</a></span></div><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="cpp comments">// Needs many overloads since no CTAD for function template arguments</code></div><div class="line number2 index1 alt1"><code class="cpp keyword bold">template</code><code class="cpp plain"><</code><code class="cpp keyword bold">class</code> <code class="cpp plain">charT></code></div><div class="line number3 index2 alt2"><code class="cpp plain">T11 quoted(</code><code class="cpp keyword bold">const</code> <code class="cpp plain">charT* s, charT delim = charT(</code><code class="cpp string">'"'</code><code class="cpp plain">), charT escape = charT(</code><code class="cpp string">'\\'</code><code class="cpp plain">));</code></div><div class="line number4 index3 alt1"><code class="cpp spaces"> </code> </div><div class="line number5 index4 alt2"><code class="cpp keyword bold">template</code><code class="cpp plain"><</code><code class="cpp keyword bold">class</code> <code class="cpp plain">charT, </code><code class="cpp keyword bold">class</code> <code class="cpp plain">traits, </code><code class="cpp keyword bold">class</code> <code class="cpp plain">Allocator></code></div><div class="line number6 index5 alt1"><code class="cpp plain">T12 quoted(</code><code class="cpp keyword bold">const</code> <code class="cpp plain">basic_string<charT, traits, Allocator>& s,</code></div><div class="line number7 index6 alt2"><code class="cpp spaces"> </code><code class="cpp plain">charT delim = charT(</code><code class="cpp string">'"'</code><code class="cpp plain">), charT escape = charT(</code><code class="cpp string">'\\'</code><code class="cpp plain">));</code></div><div class="line number8 index7 alt1"><code class="cpp spaces"> </code> </div><div class="line number9 index8 alt2"><code class="cpp keyword bold">template</code><code class="cpp plain"><</code><code class="cpp keyword bold">class</code> <code class="cpp plain">charT, </code><code class="cpp keyword bold">class</code> <code class="cpp plain">traits, </code><code class="cpp keyword bold">class</code> <code class="cpp plain">Allocator></code></div><div class="line number10 index9 alt1"><code class="cpp plain">T14 quoted(basic_string_view<charT, traits, Allocator>& s,</code></div><div class="line number11 index10 alt2"><code class="cpp spaces"> </code><code class="cpp plain">charT delim = charT(</code><code class="cpp string">'"'</code><code class="cpp plain">), charT escape = charT(</code><code class="cpp string">'\\'</code><code class="cpp plain">));</code></div></div></td></tr></tbody></table></div></div></td>
<td valign="top"><div><div id="highlighter_710262" class="syntaxhighlighter nogutter cpp"><div class="toolbar"><span><a href="#" class="toolbar_item command_help help">?</a></span></div><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="cpp comments">// Example 1: CTAD deduces s argument as in ordinary declarations</code></div><div class="line number2 index1 alt1"><code class="cpp keyword bold">template</code><code class="cpp plain"><</code><code class="cpp keyword bold">class</code> <code class="cpp plain">charT, </code><code class="cpp keyword bold">class</code> <code class="cpp plain">traits, </code><code class="cpp keyword bold">class</code> <code class="cpp plain">Allocator></code></div><div class="line number3 index2 alt2"><code class="cpp plain">T1 quoted(basic_string_view<charT, traits, Allocator>& s,</code></div><div class="line number4 index3 alt1"><code class="cpp spaces"> </code><code class="cpp plain">charT delim = charT(</code><code class="cpp string">'"'</code><code class="cpp plain">), charT escape = charT(</code><code class="cpp string">'\\'</code><code class="cpp plain">));</code></div></div></td></tr></tbody></table></div></div></td>
</tr></tbody></table>
Many other standard library function templates, such as <tt>basic_string::append</tt>,
<tt>basic_string::append()</tt>, <tt>basic_string::find()</tt>, <tt>regex_match()</tt>,
etc. have to go through similar error-prone contortions to support Function Template
Argument Deduction. Indeed, since we recommend that programmers working with text take
<tt>string_view</tt>s in their function templates, they will have to frequently
create similar manual overloads themselves.
<br><br>As just one more example, with the addition of <tt>optional</tt>, function
templates that take <tt>optional</tt> arguments, will have to sacrifice
natural Function Template Argument Deduction:
<table border="1"><tbody><tr><td colspan="2">
<div><div id="highlighter_642493" class="syntaxhighlighter nogutter cpp"><div class="toolbar"><span><a href="#" class="toolbar_item command_help help">?</a></span></div><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="cpp comments">// Point class template along the lines of P0267R8</code></div><div class="line number2 index1 alt1"><code class="cpp keyword bold">template</code><code class="cpp plain"><</code><code class="cpp keyword bold">class</code> <code class="cpp plain">T> </code><code class="cpp keyword bold">void</code> <code class="cpp plain">f(optional<T>);</code></div></div></td></tr></tbody></table></div></div></td></tr>
<tr><th>C++17</th><th>Proposed</th></tr>
<tr><td><div><div id="highlighter_110188" class="syntaxhighlighter nogutter cpp"><div class="toolbar"><span><a href="#" class="toolbar_item command_help help">?</a></span></div><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="cpp plain">f<</code><code class="cpp color1 bold">int</code><code class="cpp plain">>(7); </code><code class="cpp comments">// Do I really need to do this?</code></div></div></td></tr></tbody></table></div></div></td>
<td><div><div id="highlighter_176919" class="syntaxhighlighter nogutter cpp"><div class="toolbar"><span><a href="#" class="toolbar_item command_help help">?</a></span></div><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="cpp plain">f(7); </code><code class="cpp comments">// Proposed: No!</code></div></div></td></tr></tbody></table></div></div></td>
</tr></tbody></table>
One technical point deserves mention here. It may be that the function template parameter
is a more complex partial specialization of a class template than in the example above. For example,
<blockquote><div><div id="highlighter_516771" class="syntaxhighlighter nogutter cpp"><div class="toolbar"><span><a href="#" class="toolbar_item command_help help">?</a></span></div><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="cpp keyword bold">template</code><code class="cpp plain"><</code><code class="cpp keyword bold">typename</code> <code class="cpp plain">T> </code><code class="cpp keyword bold">void</code> <code class="cpp plain">f(pair<</code><code class="cpp color1 bold">int</code><code class="cpp plain">, T>);</code></div></div></td></tr></tbody></table></div></div></blockquote>
In such a case, we deduce the <tt>pair<int, T></tt> by following the same process
as used for alias templates in <a href="http://wg21.link/p1021r1">P1021R1</a>, thereby
deducing <tt>T</tt>. For example, <tt>f({{}, 2L})</tt> will deduce <tt>f<long></tt>,
which takes a <tt>pair<int, long></tt> as an argument.
For the technical details, see P1021R1, which has a step-by-step walkthrough
for deducing <tt>pair<int, T></tt>.
<h2>Deduction guides for function templates</h2>
<p>While Class Template Argument Deduction uses both implicit and explicit deduction guides,
Function Template Argument Deduction in effect uses only implicit guides (ordinary Function
Template Argument deduction). Given that it often proves helpful to override the implicit deduction
behavior of class templates, would the same be true for function templates? The answer is a resounding “yes”.</p>
<p><tt>std::reference_wrapper</tt> is commonly used to effect pass-by-reference
to function templates with generic parameter types, but this is rarely used outside
the standard library we believe due to the ugliness of forcing the correct deduction.
If, as we propose, deduction guides could be provided for implicit guides, unwrapping
would be straightforward, both inside the standard library and in user code:</p>
<table border="1"><tbody><tr><th>C++17</th><th>Proposed</th></tr><tr><td>
<div><div id="highlighter_9990" class="syntaxhighlighter nogutter cpp"><div class="toolbar"><span><a href="#" class="toolbar_item command_help help">?</a></span></div><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="cpp comments">// Helper for converting reference wrappers to references</code></div><div class="line number2 index1 alt1"><code class="cpp keyword bold">template</code> <code class="cpp plain"><</code><code class="cpp keyword bold">typename</code> <code class="cpp plain">T> </code><code class="cpp keyword bold">struct</code> <code class="cpp plain">unwrap { </code><code class="cpp keyword bold">using</code> <code class="cpp plain">type = T };</code></div><div class="line number3 index2 alt2"><code class="cpp keyword bold">template</code> <code class="cpp plain"><</code><code class="cpp keyword bold">typename</code> <code class="cpp plain">T> </code><code class="cpp keyword bold">struct</code> <code class="cpp plain">unwrap<std::reference_wrapper<T>> { </code><code class="cpp keyword bold">using</code> <code class="cpp plain">type = T & }</code></div><div class="line number4 index3 alt1"><code class="cpp keyword bold">template</code> <code class="cpp plain"><</code><code class="cpp keyword bold">typename</code> <code class="cpp plain">T> </code><code class="cpp keyword bold">using</code> <code class="cpp plain">unwrap_t = </code><code class="cpp keyword bold">typename</code> <code class="cpp plain">unwrap<T>::type;</code></div><div class="line number5 index4 alt2"> </div><div class="line number6 index5 alt1"> </div><div class="line number7 index6 alt2"><code class="cpp keyword bold">template</code><code class="cpp plain"><</code><code class="cpp keyword bold">typename</code> <code class="cpp plain">T> </code><code class="cpp keyword bold">void</code> <code class="cpp plain">f_impl(T t);</code></div><div class="line number8 index7 alt1"> </div><div class="line number9 index8 alt2"><code class="cpp comments">// We want f to take its argument by value or ref based</code></div><div class="line number10 index9 alt1"><code class="cpp comments">// whether or not it is a reference_wrapper</code></div><div class="line number11 index10 alt2"><code class="cpp keyword bold">template</code> <code class="cpp plain"><</code><code class="cpp keyword bold">typename</code> <code class="cpp plain">T> </code><code class="cpp keyword bold">void</code> <code class="cpp plain">f(T &&t) </code></div><div class="line number12 index11 alt1"><code class="cpp plain">{</code></div><div class="line number13 index12 alt2"><code class="cpp spaces"> </code><code class="cpp plain">f_impl<unwrap_t<T>>(t);</code></div><div class="line number14 index13 alt1"><code class="cpp plain">}</code></div></div></td></tr></tbody></table></div></div></td>
<td valign="top"><div><div id="highlighter_623768" class="syntaxhighlighter nogutter cpp"><div class="toolbar"><span><a href="#" class="toolbar_item command_help help">?</a></span></div><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="cpp comments">// Unwrap reference_wrapper with deduction guide</code></div><div class="line number2 index1 alt1"><code class="cpp keyword bold">template</code> <code class="cpp plain"><</code><code class="cpp keyword bold">typename</code> <code class="cpp plain">T> </code><code class="cpp keyword bold">void</code> <code class="cpp plain">f(T t);</code></div><div class="line number3 index2 alt2"><code class="cpp keyword bold">template</code> <code class="cpp plain"><</code><code class="cpp keyword bold">typename</code> <code class="cpp plain">T> f(reference_wrapper<T>) -> f<T &>;</code></div></div></td></tr></tbody></table></div></div></td></tr></tbody></table>
Not only does the deduction guide make the code much simpler, it moves the unwrapping
of the <tt>reference_wrapper</tt> from being hidden inside the body of <tt>f</tt> to being
advertised in <tt>f</tt>'s interface. In real life, this is often even hidden more deeply as
many implementation of, say, <tt>for_each</tt> do not unwrap reference wrappers until they
actually invoke the callable.
<p>As another example, for function templates that accept am “in” argument, it is common to want to accept
small argument types, such as <tt>int</tt>, by value and large or uncopyable types by <tt>const &</tt>.
Unfortunately, this is rarely done as the implicitly-generated rules for Function Template Argument
Deduction do not readily provide the desired behavior. With deduction guides, this again naturally simplifies
to a form that no longer requires examining the body of <tt>f</tt> to understand how arguments are passed:
</p><table border="1"><tbody><tr><th>C++17</th><th>Proposed</th></tr>
<tr><td><div><div id="highlighter_576514" class="syntaxhighlighter nogutter cpp"><div class="toolbar"><span><a href="#" class="toolbar_item command_help help">?</a></span></div><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="cpp keyword bold">template</code> <code class="cpp plain"><</code><code class="cpp keyword bold">typename</code> <code class="cpp plain">T> </code></div><div class="line number2 index1 alt1"><code class="cpp keyword bold">void</code> <code class="cpp plain">f_impl(T t);</code></div><div class="line number3 index2 alt2"> </div><div class="line number4 index3 alt1"><code class="cpp keyword bold">template</code> <code class="cpp plain"><</code><code class="cpp keyword bold">typename</code> <code class="cpp plain">T> </code><code class="cpp keyword bold">inline</code> <code class="cpp keyword bold">void</code> <code class="cpp plain">f(T && t)</code></div><div class="line number5 index4 alt2"><code class="cpp plain">{</code></div><div class="line number6 index5 alt1"><code class="cpp spaces"> </code><code class="cpp plain">do_f<</code><code class="cpp keyword bold">typename</code> <code class="cpp plain">boost::call_traits<decay_t<T>>::type>(t);</code></div><div class="line number7 index6 alt2"><code class="cpp plain">}</code></div></div></td></tr></tbody></table></div></div></td>
<td valign="top"><div><div id="highlighter_766147" class="syntaxhighlighter nogutter cpp"><div class="toolbar"><span><a href="#" class="toolbar_item command_help help">?</a></span></div><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="cpp keyword bold">template</code> <code class="cpp plain"><</code><code class="cpp keyword bold">typename</code> <code class="cpp plain">T> </code><code class="cpp keyword bold">void</code> <code class="cpp plain">f(T t);</code></div><div class="line number2 index1 alt1"><code class="cpp keyword bold">template</code> <code class="cpp plain"><</code><code class="cpp keyword bold">typename</code> <code class="cpp plain">T> f(T t) -> f<</code><code class="cpp keyword bold">typename</code> <code class="cpp plain">boost::call_traits<T>::type>;</code></div></div></td></tr></tbody></table></div></div></td></tr></tbody></table>
<b>Note: </b>Earlier versions of this paper proposed allowing deduction guides
to optionally specify which of an overloaded function template they were guiding. We defer this
both due to complexity and the absence of compelling use cases. This can
always be added later if it proves worthwhile. Indeed, class template constructors
also form an overload set, and such a feature has not proved necessary for Class Template Argument Deduction.
<script type="text/javascript">
SyntaxHighlighter.defaults['gutter'] = false;
SyntaxHighlighter.all()
</script>
</body></html>