-
Notifications
You must be signed in to change notification settings - Fork 0
/
D1167R0.html
199 lines (183 loc) · 11 KB
/
D1167R0.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
<!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" />
<script src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js"></script>
<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 div.toolbar span a.toolbar_item{
display: none !important;
}
body .syntaxhighlighter .line {
white-space: pre !important;
}
</style>
<title>Improving function templates with Class Template Argument Deduction</title>
</head>
<body>
<p>D1167R0<br>
Mike Spertus, Symantec<br>
<a href="mailto:mike_spertus@symantec.com">mike_spertus@symantec.com</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"><tr><th>C++17</th><th>Proposed</th></tr>
<tr><td>
<pre class="brush:cpp">// Example 1: “Output” version of std::quoted
// Needs many overloads since no CTAD for function template arguments
template<class charT>
T11 quoted(const charT* s, charT delim = charT('"'), charT escape = charT('\\'));
template<class charT, class traits, class Allocator>
T12 quoted(const basic_string<charT, traits, Allocator>& s,
charT delim = charT('"'), charT escape = charT('\\'));
template<class charT, class traits, class Allocator>
T14 quoted(basic_string_view<charT, traits, Allocator>& s,
charT delim = charT('"'), charT escape = charT('\\'));</pre></td>
<td valign="top"><pre class="brush:cpp">
// Example 1: Allow CTAD to deduce function template arguments
template<class charT, class traits, class Allocator>
T1 quoted(basic_string_view<charT, traits, Allocator>& s,
charT delim = charT('"'), charT escape = charT('\\'));</pre></td>
</tr>
<tr><td><pre class="brush:cpp">// Example 2: Passing 'In' parameter by value or const & by efficiency
template <typename T> void do_f(T t); // Implements f
template <typename T> inline void f(T && t)
{
do_f<typename boost::call_traits<decay_t<T>>::type>(t);
}
f(7); // Pass by-value
f(vector {1, 2, 3, 4}); // Passed by const &</pre></td>
<td valign="top"><pre class="brush:cpp">// Example 2: Allow Deduction Guides for Function Templates
template <typename T> void f(T t); // Implement here. No need to delegate
template <typename T> f(T t) -> f<typename boost::call_traits<T>::type>;
f(7); // Pass by-value
f(vector {1, 2, 3, 4}); // Passed by const &</pre></td></tr>
</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"><tr><td colspan="2">
<pre class="brush:cpp">// Point class template along the lines of P0267R8
template<class T> Point { T x; T y; }; </pre></td></tr>
<tr><th>C++17</th><th>Proposed</th></tr>
<tr><td><pre class="brush:cpp">// Function Template Argument Deduction fails
distance<double>({0.0, 0.0}, {3.0, 4.0});</pre></td>
<td><pre class="brush:cpp">// Fix by deducing argument from initializer
distance({0.0, 0.0}, {3.0, 4.0});</pre></td>
</tr></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"><tr><th>C++17</th><th>Proposed</th></tr>
<tr><td>
<pre class="brush:cpp">// Needs many overloads since no CTAD for function template arguments
template<class charT>
T11 quoted(const charT* s, charT delim = charT('"'), charT escape = charT('\\'));
template<class charT, class traits, class Allocator>
T12 quoted(const basic_string<charT, traits, Allocator>& s,
charT delim = charT('"'), charT escape = charT('\\'));
template<class charT, class traits, class Allocator>
T14 quoted(basic_string_view<charT, traits, Allocator>& s,
charT delim = charT('"'), charT escape = charT('\\'));</pre></td>
<td valign="top"><pre class="brush:cpp">
// Example 1: CTAD deduces s argument as in ordinary declarations
template<class charT, class traits, class Allocator>
T1 quoted(basic_string_view<charT, traits, Allocator>& s,
charT delim = charT('"'), charT escape = charT('\\'));</pre></td>
</tr></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"><tr><td colspan="2">
<pre class="brush:cpp">// Point class template along the lines of P0267R8
template<class T> void f(optional<T>); </pre></td></tr>
<tr><th>C++17</th><th>Proposed</th></tr>
<tr><td><pre class="brush:cpp">f<int>(7); // Do I really need to do this?</pre></td>
<td><pre class="brush:cpp">f(7); // Proposed: No!</pre></td>
</tr></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><pre class="brush:cpp">template<typename T> void f(pair<int, T>);</pre></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"><tr><th>C++17</th><th>Proposed</th></tr><tr><td>
<pre class="brush:cpp">// Helper for converting reference wrappers to references
template <typename T> struct unwrap { using type = T };
template <typename T> struct unwrap<std::reference_wrapper<T>> { using type = T & }
template <typename T> using unwrap_t = typename unwrap<T>::type;
template<typename T> void f_impl(T t);
// We want f to take its argument by value or ref based
// whether or not it is a reference_wrapper
template <typename T> void f(T &&t)
{
f_impl<unwrap_t<T>>(t);
}</pre></td>
<td valign="top"><pre class="brush:cpp">// Unwrap reference_wrapper with deduction guide
template <typename T> void f(T t);
template <typename T> f(reference_wrapper<T>) -> f<T &>;</pre></td></tr></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:
<table border="1"><tr><th>C++17</th><th>Proposed</th></tr>
<tr><td><pre class="brush:cpp">template <typename T>
void f_impl(T t);
template <typename T> inline void f(T && t)
{
do_f<typename boost::call_traits<decay_t<T>>::type>(t);
}</pre></td>
<td valign="top"><pre class="brush:cpp">template <typename T> void f(T t);
template <typename T> f(T t) -> f<typename boost::call_traits<T>::type>;</pre></td></tr></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>