root/trunk/docsrc/concepts.dd

Revision 1164, 5.5 kB (checked in by walter, 3 years ago)

initial

Line 
1 Ddoc
2
3 $(D_S Template Constraints,
4
5     $(P Templates are normally overloaded and matched based on the
6     template arguments being matched to the template parameters.
7     The template parameters can specify specializations, so that
8     the template argument must match particular type patterns.
9     Similarly, template value arguments can be constrained to
10     match particular types.)
11
12     $(P But this has its limitations. Many times there are
13     arbitrarily more
14     complex criteria for what should be accepted by the template.
15     This can be used to:
16     )
17
18     $(UL
19     $(LI more finely discriminate about which
20      template gets instantiated for given arguments)
21     $(LI provides better self-documentation about what
22      characteristics template parameters must have)
23     $(LI can provide better diagnostics when arguments don't match,
24      rather than an obscure error message based on the irrelevant
25      (to the user) internal details of the template implementation)
26     )
27
28     $(P Constraints address this by simply providing an
29     expression that must evaluate at compile time to true
30     after the arguments are matched to the parameters.
31     If it is true, then that template is a valid match for
32     the arguments, if not, then it is not and is passed over
33     during overload matching.)
34
35     $(P The constraint expression follows the template declaration
36     and the $(CODE if) keyword:)
37
38 ---
39 template Foo(int N)
40         if (N & 1)
41 {
42     ...
43 }
44 ---
45
46     $(P which constrains the template $(CODE Foo) to match only if its
47     argument
48     is an odd integer. Arbitrarily complex criteria can be used, as
49     long as it can be computed at compile time. For example, here's
50     a template that only accepts prime numbers:
51     )
52
53 ---
54 bool isprime(int n)
55 {
56     if (n < 1 || (n & 1) == 0)
57     return false;
58     if (n > 3)
59     {
60     for (auto i = 3; i * i < n; i += 2)
61     {
62         if ((n % i) == 0)
63         return false;
64     }
65     }
66     return true;
67 }
68
69 template Foo(int N)
70     if (isprime(N))
71 {
72     ...
73 }
74
75 Foo!(5)    // ok, 5 is prime
76 Foo!(6)    // no match for Foo
77 ---
78
79     $(P Type constraints can be complex, too. For example, a template
80     Bar that will accept any floating point type using the traditional
81     type specializations:
82     )
83 ---
84 template Bar(T:float)
85 {
86    ...
87 }
88 template Bar(T:double)
89 {
90    ...
91 }
92 template Bar(T:real)
93 {
94    ...
95 }
96 ---
97     $(P and the template implementation body must be duplicated
98     three times. But with constraints, this can be specified
99     with one template:
100     )
101 ---
102 template Bar(T)
103     if (is(T == float) || is(T == double) || is(T == real))
104 {
105    ...
106 }
107 ---
108     $(P This can be simplified by using the $(CODE isFloatingPoint)
109     template in library module $(CODE std.traits):
110     )
111 ---
112 import std.traits;
113 template Bar(T)
114     if (isFloatingPoint!(T))
115 {
116    ...
117 }
118 ---
119
120     $(P Characteristics of types can be tested, such as if
121     a type can be added:
122     )
123
124 ---
125 // Returns true if instances of type T can be added
126 template isAddable(T)
127 {   // Works by attempting to add two instances of type T
128     const isAddable = __traits(compiles, (T t) { return t + t; });
129 }
130
131 int Foo(T)(T t)
132     if (isAddable!(T))
133 {
134     return 3;
135 }
136
137 struct S
138 {
139     void opAdd(S s) { }   // an addable struct type
140 }
141
142 void main()
143 {
144     Foo(4);   // succeeds
145     S s;
146     Foo(s);   // succeeds
147     Foo("a"); // fails to match
148 }
149 ---
150
151     $(P Since any expression that can be computed at compile time
152     is allowed as a constraint, constraints can be composed:
153     )
154
155 ---
156 int Foo(T)(T t)
157     if (isAddable!(T) && isMultipliable!(T))
158 {
159     return 3;
160 }
161 ---
162
163     $(P A more complex constraint can specify a list of operations
164     that must be doable with the type, such as $(CODE isStack) which
165     specifies the constraints that a stack type must have:)
166
167 ----
168 template isStack(T)
169 {
170     const isStack =
171         __traits(compiles,
172           (T t)
173           {   T.value_type v = top(t);
174               push(t, v);
175               pop(t);
176               if (empty(t)) { }
177           });
178 }
179
180 template Foo(T)
181     if (isStack!(T))
182 {
183     ...
184 }
185 ----
186
187     $(P and constraints can deal with multiple parameters:)
188
189 ---
190 template Foo(T, int N)
191     if (isAddable!(T) && isprime(N))
192 {
193     ...
194 }
195 ---
196
197 <h2>Overloading based on Constraints</h2>
198
199     $(P Given a list of overloaded templates with the same name,
200     constraints act as a yes/no filter to determine the list
201     of candidates for a match.
202     Overloading based on constraints can thus be achieved by
203     setting up constraint expressions that are mutually exclusive.
204     For example, overloading template $(CODE Foo) so that one
205     takes odd integers and the other even:
206     )
207 ---
208 template Foo(int N) if (N & 1)    { ... } // A
209 template Foo(int N) if (!(N & 1)) { ... } // B
210 ...
211 Foo!(3)    // instantiates A
212 Foo!(64)   // instantiates B
213 ---
214
215     $(P Constraints are not involved with determining which
216     template is more specialized than another.
217     )
218
219 ---
220 void foo(T, int N)()        if (N & 1) { ... } // A
221 void foo(T : int, int N)()  if (N > 3) { ... } // B
222 ...
223 foo!(int, 7)();   // picks B, more specialized
224 foo!(int, 1)();   // picks A, as it fails B's constraint
225 foo!("a", 7)();   // picks A
226 foo!("a", 4)();   // error, no match
227 ---
228
229 <h2>References</h2>
230
231     $(UL
232     $(LI $(LINK2 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2081.pdf, Concepts (Revision 1))
233      by Douglas Gregor and Bjarne Stroustrup
234     )
235     )
236
237 )
238
239 Macros:
240     TITLE=Template Constraints
241     WIKI=Constraints
242 META_KEYWORDS=D Programming Language, constraints, template, concepts, C++
243 META_DESCRIPTION=Going beyond type patterns to constrain template instantiations.
Note: See TracBrowser for help on using the browser.