-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCTAD_alias_examples.html
120 lines (101 loc) · 7.14 KB
/
CTAD_alias_examples.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
<!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>CTAD for alias templates algorithm examples</title>
</head>
<body>
<p>Mike Spertus, Symantec<br>
<a href="mailto:mike_spertus@symantec.com">mike_spertus@symantec.com</a><br>
</p>
<h1>CTAD for alias templates algorithm examples</h1>
<h1>Algorithm Overview</h1>
For deriving deduction guides for the alias templates from guides in the class, we use the following approach (for which we are very grateful for the invaluable assistance of Richard Smith):
<ol><li>Deduce template parameters for the deduction guide by deducing the right hand side of
the deduction guide from the alias template. We do not require that this deduces all the template
parameters as nondeducible contexts may of course occur in general</li>
<li>Substitute any deductions made back into the deduction guides</li>
<li>Derive the corresponding deduction guide for the alias template by
deducing the alias from the result type. Note that a constraint may be necessary
as whether and how to deduce the alias from the result type may depend on the
actual argument types.</li></ol>
<h1>Conceptual description and example</h1>
<p>This section gives Richard's nice discussion on how to think about the algorithm.</p>
Perhaps a nice way to think about the algorithm here is that we're applying (bidirectional) type unification between the produced type of the deduction guide and the alias template. Specifically, we're attempting to find a set of equalities between type expressions involving deduction guide template parameters and type expressions involving alias template parameters. Example:
<blockquote><pre class="brush:cpp">template<typename T, typename U, typename V> struct Z {
Z(typename T:::template R<U>, ...);
};
struct Q { template<typename U> struct R {}; };
template<typename T, typename U, typename V>
Z(typename T:::template R<U>, V&) -> Z<T, U, V*>
template<typename X, typename Y> using W = Z<Q, X*, Y>;
W w = {Q::X<int*>(), w};</pre></blockquote>
We take the
<blockquote><pre class="brush:cpp">template<typename T, typename U, typename V>
Z(typename T:::template R<U>, V&) -> Z<T, U, V*></pre></blockquote>
deduction guide and we want to rewrite it as
<blockquote><pre class="brush:cpp">template<typename T, typename U, typename V, typename X, typename Y>
W(typename T:::template R<U>, V&) -> W<X, Y>;</pre></blockquote>
subject to some equivalences between <code>T</code>, <code>U</code>, <code>V</code>, <code>X</code>, <code>Y</code>. So we attempt to unify <code>Z<Q, X*, Y></code> with <code>Z<T, U, V*></code>. This gives:
<blockquote>
<code>T = Q<br>
U = X<br>
V = ???<br>
X = ???<br>
Y = V*</code></blockquote>
[We only care about cases where one side can be reduced to a template parameter. The other cases are:<ul>
<li> both sides are non-deduced contexts: we can't deduce anything here (eg, <code>std::decay_t<T> == std::decay_t<U></code>)</li>
<li> one side is non-deduced and the other side is a non-trivial type/non-type expression: we can't deduce anything here (eg, <code>T* = std::decay_t<U></code>)</li>
<li>both sides are non-trivial type/non-type expressions and can't both be reduced: deduction fails (eg, <code>T* = U&</code>)</li></ul><br>
]
<p>Now, complete the unification:<ul>
<li>for each parameter in the deduction guide whose value is expressed in terms of a parameter of the alias template, substitute that away everywhere (including in the RHS of substitutions<a href="#fn1">*</a>):
<blockquote><pre class="brush:cpp">template<typename V, typename X, typename Y>
W(Q:::R<X>, V&) -> W<X, Y>;</pre></blockquote></li>
<li> and likewise for each parameter in the alias template whose value is expressed in terms of a parameter of the deduction guide:
<blockquote><pre class="brush:cpp">template<typename V, typename X>
W(Q:::R<X>, V&) -> W<X, V*>;</pre></blockquote>
... and I believe that's the deduction guide we're looking for.</li>
</ul>
<a name="fn1">* In the actual algorithm we get -- essentially -- this effect by doing the first round of substitutions before we do the deduction in the opposite direction.</a>
<h1>Additional examples</h1>
<h2>Fixing an argument</h2>
<blockquote><pre class="brush:cpp">template<class T> using P = pair<int, T>;</pre></blockquote>
Naively using the deduction guides from pair is not ideal because they
cannot necessarily deduce objects of type <tt>P</tt> even
from arguments that should obviously work, like <tt>P({}, 0)</tt>. However,
let us apply the above procedure. The relevant deduction guide is
<blockquote><pre class="brush:cpp">template<class A, class B> pair(A, B) -> pair<A, B></pre></blockquote>
Deducing <code>(A, B)</code> from <code>(int, T)</code> yield <code>int</code> for <code>A</code>
and <code>T</code> for <code>B</code>. Now substitute back into the deduction guide to get
a new deduction guide
<blockquote><pre class="brush:cpp">template<class T> pair(int, T) -> pair<int, T>;</pre></blockquote>
Deducing the template arguments for the alias template from this gives us the following deduction guide for the alias template
<blockquote><pre class="brush:cpp">template<class T> P(int, T) -> P<T>;</pre></blockquote>
<h2>Renaming</h2>
In the following example, the programmer just wants to give a class template a shorter name
without changing behavior
<blockquote><pre class="brush:cpp">template<class T> class VeryLongNameXXXXX { /* ... */ };
template<class T> class VeryLongNameXXXXX(T) -> VeryLongNameXXXXX<decay_t<T>>;
// Alias that programmer expects to be the same as original type
template<class T> using MyAbbrev = VeryLongNameXXXXXX<T>;</pre></blockquote>
In this case, plugging in <code>(A)</code> for the nondeducible context <code>(decay_t<T>)</code> does not deduce anything, so the deduction guide remains the same. Deducing the template arguments
for the (identical!) alias template is easy, yielding the desired deduction guide for the alias template.
<blockquote><pre class="brush:cpp">template<class T> class MyAbbrev(T) -> MyAbbrev<decay_t<T>>;</pre></blockquote>
<script type="text/javascript">
SyntaxHighlighter.defaults['gutter'] = false;
SyntaxHighlighter.all()
</script>
</body></html>