-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathD1168R0.html
198 lines (186 loc) · 9.83 KB
/
D1168R0.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
<!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>How to make Terse Notation soar with Class Template Argument Deduction</title>
</head>
<body>
<p>P1168R0<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>How to make Terse Notation soar with Class Template Argument Deduction</h1>
Terse concept notation along the lines of <a href="http://wg21.link/p1141r1">P1141R1</a> has
the potential to powerfully make generic programming look more like “regular
programming”. As it is important for the initial release of concepts and terse notation to make
a good first impression, this paper discusses how Class Template Argument
Deduction can pitch in and help make the release of terse notation as successful as possible.
as illustrated by the following example (note that <tt>Curve</tt> is a concept).
<table border="1"><tr><th>C++17 + P1141R1</th><th>Proposed</th></tr>
<tr><td>
<pre class="brush:cpp">auto f(Curve auto &c)
-> pair<decltype(c), pmr::vector<typename decltype(c.ctrl_pts)::value_type>>
{
Point<decltype(c.x_min())> top_left{c.x_min(), c.y_max()};
screen->line<decltype(p.x)>(p, {c.x_min(), c.y_max()});
pmr::vector<typename decltype(c.ctrl_pts)::value_type> cp(c.ctrl_pts.begin(), c.ctrl_pts.end(), mem_res);
return {c, cp };
};</pre></td>
<td valign="top">
<pre class="brush:cpp">pair auto f(Curve auto &c, basic_ostream auto logger)
{
Point top_left{c.x_min(), c.y_max()};
screen->line(top_left, {c.x_min(), c.y_max()});
pmr::vector cp(c.ctrl_pts.begin(), c.ctrl_pts.end(), mem_res);
return {c, cp};
};</pre></td>
</tr></table>
What is going on here? Since function template arguments in
terse notation often do not have named types, the easier
it is to create new objects from existing objects without
having to explicitly refer to their types, the more natural code
will be. Since Class Template Argument Deduction
provides inferenced creation of constrained objects
just as concepts provide inferenced usage of constrained objects
(thereby addressing complementary problems), it can really
help in such situations as the above example shows. For a stunning
example of how much robust Class Template Argument Deduction can
enhance concepts code, see the argument deduction <a href="#ex1">example</a>
near the end of this paper.
<p>While C++17 Class Template Argument Deduction can often be
used in such situations (e.g., if the <tt>pmr::vector</tt> above
had been an ordinary <tt>vector</tt>), the example above
was crafted to illustrate the value of potential improvements
to Class Template Argument Deduction, such as return type
deduction below, and aggregate and type alias deduction. Such
basic "filling of holes" would help a lot as illustrated in the
example, and is covered in <a href="http://wg21.link/p1021r1">P1021R1</a> and
<a href="http://wg21.link/p1167r0">P116R0</a>. The remainder
of this paper focuses specifically on aligning Class Template
Argument Deduction Inferencing with Constrained Type Inferencing.
<h2>The proposal</h2>
Our proposal is simply that wherever P1141R1 allows a Concept-constrained
<tt>auto</tt>, a class template can be used as well with the same
rules for independent resolution and forwarding references. Of course,
if a different approach from P1141 is adopted for constrained declarations,
this proposal should follow that. Likewise, we do not take a position on where
<tt>auto</tt> should be required, simply that the same rules should apply to CTAD inferencing and concept inferencing to best maintain consistency between concepts and types.
<p>Let us look at some particular cases.</p>
<h3>Ordinary declarations</h3>
In P1141R1, it is mentioned that in
<blockquote><pre class="brush:cpp">Constraint auto f1();</pre></blockquote>
it should be possible to omit the <tt>auto</tt> to get
<blockquote><pre class="brush:cpp">Constraint f1();</pre></blockquote>
As justification, P1141R1 specifically refers to Class Template Argument Deduction allowing
<blockquote><pre class="brush:cpp">std::tuple x = foo();</pre></blockquote>
By the same reasoning, it makes sense for us to be consistent in the other
direction and allow
<blockquote><pre class="brush:cpp">std::tuple auto x = foo();</pre></blockquote>
Otherwise, the programmer has to remember a bunch of special-cased
rules as to which kinds of deduced declarations can accept an <tt>auto</tt>
or not.
<h3>Return type deduction</h3>
Likewise, just like one can say
<blockquote><pre class="brush:cpp">Constraint auto f1();</pre></blockquote>
one should also be able to say
<blockquote><pre class="brush:cpp">tuple auto f1();</pre></blockquote>
to make explicit that constrained type deduction is taking place (In
this context, we are using the phrase “constrained type
deduction” to refer to the fact that the deduced type
is given more specifically than just a lone <tt>auto</tt>).
The example given at the top of this paper of <tt>f</tt>
returning
<blockquote><pre class="brush:cpp">pair auto</pre></blockquote>
instead of
<blockquote><pre class="brush:cpp">pair<decltype(c), pmr::vector<typename decltype(c.ctrl_pts)::value_type>></pre></blockquote>
illustrates just how much this can simplify code.
<p>Notes:</p>
<ul><li>As with normal return type deduction, the function needs to have
a <tt>return</tt> statement, and all <tt>return</tt> statements must
generate the same type. In <a href="http://wg21.link/p1021r0">P1021R0</a>, it was proposed that the <tt>return</tt> statements could have different types, but
this is no longer proposed after feedback from compiler vendors.</li>
<li>This proposal also follows the principal that returning a value should behave like initialization:
<blockquote><pre class="brush:cpp">tuple t = {1, "foo"};
tuple auto g() { return {1, "foo"}; }</pre></blockquote></li></ul>
<h3>Argument deduction</h3>
As P1141R0 allows us to say
<blockquote><pre class="brush:cpp">void f1(Constraint auto x);</pre></blockquote>
one should also be able to indicate that a declaration has its arguments
deduced by
<blockquote><pre class="brush:cpp">void f1(tuple auto x);</pre></blockquote>
This is not only more consistent, but we think it can have a huge impact on facilitating
terse notation as now almost any function template could be written using natural function notation as
shown by the following example (which also demonstrates the value of partially-specialized
template argument lists as proposed in P1021R0)
extension
<a name="ex1"></a><table border="1"><tr><th>C++17 + P1141R1</th><th>Proposed</th></tr>
<tr><td>
<pre class="brush:cpp">// We need an explicit template here because of confusing mix of both class template and concept arguments
template<class CharT, class Traits>
auto f(Curve auto &c, basic_ostream<charT, Traits> logger)
-> pair<decltype(c), pmr::vector<typename decltype(c.ctrl_pts)::value_type>>
{
Point<decltype(c.x_min())> top_left{c.x_min(), c.y_max()};
screen->line<decltype(p.x)>(p, {c.x_min(), c.y_max()});
logger << "Drew line\n";
pmr::vector<typename decltype(c.ctrl_pts)::value_type> cp(c.ctrl_pts.begin(), c.ctrl_pts.end(), mem_res);
logger << "Got control points: ";
// Hard to specify ostream_iterator template args
copy(cp.begin(), cp.end(),
ostream_iterator<decltype(cp[0]),
typename decltype(logger)::char_type,
typename decltype(logger)::traits_type>(logger, ", "));
return {c, cp };
};</pre></td>
<td valign="top">
<pre class="brush:cpp">// “auto” constraints consistently indicate which arguments are deduced
pair auto f(Curve auto &c, basic_ostream auto logger)
{
Point auto top_left{c.x_min(), c.y_max()};
screen->line(top_left, {c.x_min(), c.y_max()});
logger << "Drew line\n";
pmr::vector cp(c.ctrl_pts.begin(), c.ctrl_pts.end(), mem_res);
logger << "Got control points: ";
// See P1021R1 for partially-specializing ostream_iterator
copy(cp.begin(), cp.end(),
ostream_iterator<decltype(cp[0])>(logger, ", "));
return {c, cp};
};</pre></td>
</tr></table>
We think things like the above example will be very common, and,
without this proposal, terse notation will not be applicable to
many function templates.
<h3>Specialization</h3>
As Zhihao Yuan notes, the partially template argument list support proposed in
P1167R0 naturally supports the useful alignment
<blockquote><pre class="brush:cpp">tuple<Copyable> t(1);</pre></blockquote>
<!-- Notes:
Should pair<Regular, vector> work as the return type? -->
<!-- <h2>Futures</h2>
The proposals in this paper not only immediately increase consistency, but
they fit nicely with possible future evolution
<h3>Concept base-class flexibility</h3>
<h3>Deduction guides for concepts</h3>
While it was pointed out above that during object creation an
actual type, rather than just its requirements, needs to be
provided, that need not be true.-->
<script type="text/javascript">
SyntaxHighlighter.defaults['gutter'] = false;
SyntaxHighlighter.all()
</script>
</body>
</html>