| 1 |
Ddoc |
|---|
| 2 |
|
|---|
| 3 |
$(SPEC_S Templates, |
|---|
| 4 |
|
|---|
| 5 |
$(BLOCKQUOTE |
|---|
| 6 |
I think that I can safely say that nobody understands template mechanics. -- Richard Deyman |
|---|
| 7 |
) |
|---|
| 8 |
|
|---|
| 9 |
$(P Templates are D's approach to generic programming. |
|---|
| 10 |
Templates are defined with a $(I TemplateDeclaration): |
|---|
| 11 |
) |
|---|
| 12 |
|
|---|
| 13 |
$(GRAMMAR |
|---|
| 14 |
$(GNAME TemplateDeclaration): |
|---|
| 15 |
$(B template) $(GLINK TemplateIdentifier) $(B $(LPAREN)) $(GLINK TemplateParameterList) $(B $(RPAREN)) $(V2 $(GLINK Constraint)$(SUB $(I opt))) |
|---|
| 16 |
$(B {) $(GLINK2 module, DeclDefs) $(B }) |
|---|
| 17 |
|
|---|
| 18 |
$(GNAME TemplateIdentifier): |
|---|
| 19 |
$(I Identifier) |
|---|
| 20 |
|
|---|
| 21 |
$(GNAME TemplateParameterList): |
|---|
| 22 |
$(I TemplateParameter) |
|---|
| 23 |
$(V2 $(I TemplateParameter) , |
|---|
| 24 |
) $(I TemplateParameter) , $(I TemplateParameterList) |
|---|
| 25 |
|
|---|
| 26 |
$(GNAME TemplateParameter): |
|---|
| 27 |
$(GLINK TemplateTypeParameter) |
|---|
| 28 |
$(GLINK TemplateValueParameter) |
|---|
| 29 |
$(GLINK TemplateAliasParameter) |
|---|
| 30 |
$(GLINK TemplateTupleParameter) |
|---|
| 31 |
$(V2 $(GLINK TemplateThisParameter)) |
|---|
| 32 |
) |
|---|
| 33 |
|
|---|
| 34 |
$(P The body of the $(I TemplateDeclaration) must be syntactically correct |
|---|
| 35 |
even if never instantiated. Semantic analysis is not done until |
|---|
| 36 |
instantiated. A template forms its own scope, and the template |
|---|
| 37 |
body can contain classes, structs, types, enums, variables, |
|---|
| 38 |
functions, and other templates. |
|---|
| 39 |
) |
|---|
| 40 |
$(P |
|---|
| 41 |
Template parameters can be types, values, symbols, or tuples. |
|---|
| 42 |
Types can be any type. |
|---|
| 43 |
Value parameters must be of an integral type, floating point |
|---|
| 44 |
type, or string type and |
|---|
| 45 |
specializations for them must resolve to an integral constant, |
|---|
| 46 |
floating point constant, null, or a string literal. |
|---|
| 47 |
Symbols can be any non-local symbol. |
|---|
| 48 |
Tuples are a sequence of 0 or more types, values or symbols. |
|---|
| 49 |
) |
|---|
| 50 |
$(P |
|---|
| 51 |
Template parameter specializations |
|---|
| 52 |
constrain the values or types the $(I TemplateParameter) can |
|---|
| 53 |
accept. |
|---|
| 54 |
) |
|---|
| 55 |
$(P |
|---|
| 56 |
Template parameter defaults are the value or type to use for the |
|---|
| 57 |
$(I TemplateParameter) in case one is not supplied. |
|---|
| 58 |
) |
|---|
| 59 |
|
|---|
| 60 |
<h2>Explicit Template Instantiation</h2> |
|---|
| 61 |
|
|---|
| 62 |
$(P |
|---|
| 63 |
Templates are explicitly instantiated with: |
|---|
| 64 |
) |
|---|
| 65 |
|
|---|
| 66 |
$(GRAMMAR |
|---|
| 67 |
$(GNAME TemplateInstance): |
|---|
| 68 |
$(GLINK TemplateIdentifier) $(B !$(LPAREN)) $(GLINK TemplateArgumentList) $(B $(RPAREN)) |
|---|
| 69 |
$(V2 $(GLINK TemplateIdentifier) $(B !) $(GLINK TemplateSingleArgument)) |
|---|
| 70 |
|
|---|
| 71 |
$(GNAME TemplateArgumentList): |
|---|
| 72 |
$(GLINK TemplateArgument) |
|---|
| 73 |
$(V2 $(GLINK TemplateArgument) , |
|---|
| 74 |
) $(GLINK TemplateArgument) , $(I TemplateArgumentList) |
|---|
| 75 |
|
|---|
| 76 |
$(GNAME TemplateArgument): |
|---|
| 77 |
$(GLINK2 declaration, Type) |
|---|
| 78 |
$(ASSIGNEXPRESSION) |
|---|
| 79 |
$(I Symbol) |
|---|
| 80 |
|
|---|
| 81 |
$(GNAME Symbol): |
|---|
| 82 |
$(I SymbolTail) |
|---|
| 83 |
$(B .) $(I SymbolTail) |
|---|
| 84 |
|
|---|
| 85 |
$(GNAME SymbolTail): |
|---|
| 86 |
$(I Identifier) |
|---|
| 87 |
$(I Identifier) $(B .) $(I SymbolTail) |
|---|
| 88 |
$(GLINK TemplateInstance) |
|---|
| 89 |
$(GLINK TemplateInstance) $(B .) $(I SymbolTail) |
|---|
| 90 |
|
|---|
| 91 |
$(V2 |
|---|
| 92 |
$(GNAME TemplateSingleArgument): |
|---|
| 93 |
$(I Identifier) |
|---|
| 94 |
$(GLINK2 declaration, BasicTypeX) |
|---|
| 95 |
$(GLINK2 lex, CharacterLiteral) |
|---|
| 96 |
$(GLINK2 lex, StringLiteral) |
|---|
| 97 |
$(GLINK2 lex, IntegerLiteral) |
|---|
| 98 |
$(GLINK2 lex, FloatLiteral) |
|---|
| 99 |
$(B true) |
|---|
| 100 |
$(B false) |
|---|
| 101 |
$(B null) |
|---|
| 102 |
$(B __FILE__) |
|---|
| 103 |
$(B __LINE__) |
|---|
| 104 |
) |
|---|
| 105 |
) |
|---|
| 106 |
|
|---|
| 107 |
$(P |
|---|
| 108 |
Once instantiated, the declarations inside the template, called |
|---|
| 109 |
the template members, are in the scope |
|---|
| 110 |
of the $(I TemplateInstance): |
|---|
| 111 |
) |
|---|
| 112 |
|
|---|
| 113 |
------ |
|---|
| 114 |
template TFoo(T) { alias T* t; } |
|---|
| 115 |
... |
|---|
| 116 |
TFoo!(int).t x; // declare x to be of type int* |
|---|
| 117 |
------ |
|---|
| 118 |
|
|---|
| 119 |
$(V2 |
|---|
| 120 |
$(P If the $(GLINK TemplateArgument) is one token long, the parentheses can be omitted: |
|---|
| 121 |
) |
|---|
| 122 |
--- |
|---|
| 123 |
TFoo!int.t x; // same as TFoo!(int).t x; |
|---|
| 124 |
--- |
|---|
| 125 |
) |
|---|
| 126 |
|
|---|
| 127 |
$(P |
|---|
| 128 |
A template instantiation can be aliased: |
|---|
| 129 |
) |
|---|
| 130 |
|
|---|
| 131 |
------ |
|---|
| 132 |
template TFoo(T) { alias T* t; } |
|---|
| 133 |
alias TFoo!(int) abc; |
|---|
| 134 |
abc.t x; // declare x to be of type int* |
|---|
| 135 |
------ |
|---|
| 136 |
|
|---|
| 137 |
$(P |
|---|
| 138 |
Multiple instantiations of a $(I TemplateDeclaration) with the same |
|---|
| 139 |
$(I TemplateArgumentList), before implicit conversions, |
|---|
| 140 |
all will refer to the same instantiation. |
|---|
| 141 |
For example: |
|---|
| 142 |
) |
|---|
| 143 |
|
|---|
| 144 |
------ |
|---|
| 145 |
template TFoo(T) { T f; } |
|---|
| 146 |
alias TFoo!(int) a; |
|---|
| 147 |
alias TFoo!(int) b; |
|---|
| 148 |
... |
|---|
| 149 |
a.f = 3; |
|---|
| 150 |
assert(b.f == 3); // a and b refer to the same instance of TFoo |
|---|
| 151 |
------ |
|---|
| 152 |
|
|---|
| 153 |
$(P |
|---|
| 154 |
This is true even if the $(I TemplateInstance)s are done in |
|---|
| 155 |
different modules. |
|---|
| 156 |
) |
|---|
| 157 |
|
|---|
| 158 |
$(P |
|---|
| 159 |
Even if template arguments are implicitly converted to the same |
|---|
| 160 |
template parameter type, they still refer to different instances: |
|---|
| 161 |
) |
|---|
| 162 |
|
|---|
| 163 |
----- |
|---|
| 164 |
struct TFoo(int x) { } |
|---|
| 165 |
static assert(is(TFoo!(3) == TFoo!(2 + 1))); // 3 and 2+1 are both 3 of type int |
|---|
| 166 |
static assert(!is(TFoo!(3) == TFoo!(3u))); // 3u and 3 are different types |
|---|
| 167 |
----- |
|---|
| 168 |
$(P |
|---|
| 169 |
If multiple templates with the same $(I TemplateIdentifier) are |
|---|
| 170 |
declared, they are distinct if they have a different number of |
|---|
| 171 |
arguments or are differently specialized. |
|---|
| 172 |
) |
|---|
| 173 |
$(P |
|---|
| 174 |
For example, a simple generic copy template would be: |
|---|
| 175 |
) |
|---|
| 176 |
|
|---|
| 177 |
------ |
|---|
| 178 |
template TCopy(T) |
|---|
| 179 |
{ |
|---|
| 180 |
void copy(out T to, T from) |
|---|
| 181 |
{ |
|---|
| 182 |
to = from; |
|---|
| 183 |
} |
|---|
| 184 |
} |
|---|
| 185 |
------ |
|---|
| 186 |
|
|---|
| 187 |
$(P |
|---|
| 188 |
To use the template, it must first be instantiated with a specific |
|---|
| 189 |
type: |
|---|
| 190 |
) |
|---|
| 191 |
|
|---|
| 192 |
------ |
|---|
| 193 |
int i; |
|---|
| 194 |
TCopy!(int).copy(i, 3); |
|---|
| 195 |
------ |
|---|
| 196 |
|
|---|
| 197 |
<h2>Instantiation Scope</h2> |
|---|
| 198 |
|
|---|
| 199 |
$(P |
|---|
| 200 |
$(I TemplateInstantance)s are always performed in the scope of where |
|---|
| 201 |
the $(I TemplateDeclaration) is declared, with the addition of the |
|---|
| 202 |
template parameters being declared as aliases for their deduced types. |
|---|
| 203 |
) |
|---|
| 204 |
$(P |
|---|
| 205 |
For example: |
|---|
| 206 |
) |
|---|
| 207 |
|
|---|
| 208 |
$(BR)$(BR) |
|---|
| 209 |
$(U module a) |
|---|
| 210 |
------ |
|---|
| 211 |
template TFoo(T) { void bar() { func(); } } |
|---|
| 212 |
------ |
|---|
| 213 |
|
|---|
| 214 |
$(U module b) |
|---|
| 215 |
------ |
|---|
| 216 |
import a; |
|---|
| 217 |
|
|---|
| 218 |
void func() { } |
|---|
| 219 |
alias TFoo!(int) f; // error: func not defined in module a |
|---|
| 220 |
------ |
|---|
| 221 |
|
|---|
| 222 |
$(P |
|---|
| 223 |
and: |
|---|
| 224 |
) |
|---|
| 225 |
|
|---|
| 226 |
$(BR)$(BR) |
|---|
| 227 |
$(U module a) |
|---|
| 228 |
------ |
|---|
| 229 |
template TFoo(T) { void bar() { func(1); } } |
|---|
| 230 |
void func(double d) { } |
|---|
| 231 |
------ |
|---|
| 232 |
|
|---|
| 233 |
$(U module b) |
|---|
| 234 |
------ |
|---|
| 235 |
import a; |
|---|
| 236 |
|
|---|
| 237 |
void func(int i) { } |
|---|
| 238 |
alias TFoo!(int) f; |
|---|
| 239 |
... |
|---|
| 240 |
f.bar(); // will call a.func(double) |
|---|
| 241 |
------ |
|---|
| 242 |
|
|---|
| 243 |
$(P |
|---|
| 244 |
$(I TemplateParameter) specializations and default |
|---|
| 245 |
values are evaluated in the scope of the $(I TemplateDeclaration). |
|---|
| 246 |
) |
|---|
| 247 |
|
|---|
| 248 |
<h2>Argument Deduction</h2> |
|---|
| 249 |
|
|---|
| 250 |
$(P The types of template parameters are deduced for a particular |
|---|
| 251 |
template instantiation by comparing the template argument with |
|---|
| 252 |
the corresponding template parameter. |
|---|
| 253 |
) |
|---|
| 254 |
|
|---|
| 255 |
$(P For each template parameter, the following rules are applied in |
|---|
| 256 |
order until a type is deduced for each parameter: |
|---|
| 257 |
) |
|---|
| 258 |
|
|---|
| 259 |
$(OL |
|---|
| 260 |
$(LI If there is no type specialization for the parameter, |
|---|
| 261 |
the type of the parameter is set to the template argument.) |
|---|
| 262 |
|
|---|
| 263 |
$(LI If the type specialization is dependent on a type parameter, |
|---|
| 264 |
the type of that parameter is set to be the corresponding part |
|---|
| 265 |
of the type argument.) |
|---|
| 266 |
|
|---|
| 267 |
$(LI If after all the type arguments are examined there are any |
|---|
| 268 |
type parameters left with no type assigned, they are assigned |
|---|
| 269 |
types corresponding to the template argument in the same position |
|---|
| 270 |
in the $(I TemplateArgumentList).) |
|---|
| 271 |
|
|---|
| 272 |
$(LI If applying the above rules does not result in exactly one |
|---|
| 273 |
type for each template parameter, then it is an error.) |
|---|
| 274 |
) |
|---|
| 275 |
|
|---|
| 276 |
$(P For example:) |
|---|
| 277 |
|
|---|
| 278 |
------ |
|---|
| 279 |
template TFoo(T) { } |
|---|
| 280 |
alias TFoo!(int) Foo1; // (1) T is deduced to be int |
|---|
| 281 |
alias TFoo!(char*) Foo2; // (1) T is deduced to be char* |
|---|
| 282 |
|
|---|
| 283 |
template TBar(T : T*) { } |
|---|
| 284 |
alias TBar!(char*) Foo3; // (2) T is deduced to be char |
|---|
| 285 |
|
|---|
| 286 |
template TAbc(D, U : D[]) { } |
|---|
| 287 |
alias TAbc!(int, int[]) Bar1; // (2) D is deduced to be int, U is int[] |
|---|
| 288 |
alias TAbc!(char, int[]) Bar2; // (4) error, D is both char and int |
|---|
| 289 |
|
|---|
| 290 |
template TDef(D : E*, E) { } |
|---|
| 291 |
alias TDef!(int*, int) Bar3; // (1) E is int |
|---|
| 292 |
// (3) D is int* |
|---|
| 293 |
------ |
|---|
| 294 |
|
|---|
| 295 |
$(P Deduction from a specialization can provide values |
|---|
| 296 |
for more than one parameter: |
|---|
| 297 |
) |
|---|
| 298 |
|
|---|
| 299 |
--- |
|---|
| 300 |
template Foo(T: T[U], U) |
|---|
| 301 |
{ |
|---|
| 302 |
... |
|---|
| 303 |
} |
|---|
| 304 |
|
|---|
| 305 |
Foo!(int[long]) // instantiates Foo with T set to int, U set to long |
|---|
| 306 |
--- |
|---|
| 307 |
|
|---|
| 308 |
$(P When considering matches, a class is |
|---|
| 309 |
considered to be a match for any super classes or interfaces: |
|---|
| 310 |
) |
|---|
| 311 |
|
|---|
| 312 |
------ |
|---|
| 313 |
class A { } |
|---|
| 314 |
class B : A { } |
|---|
| 315 |
|
|---|
| 316 |
template TFoo(T : A) { } |
|---|
| 317 |
alias TFoo!(B) Foo4; // (3) T is B |
|---|
| 318 |
|
|---|
| 319 |
template TBar(T : U*, U : A) { } |
|---|
| 320 |
alias TBar!(B*, B) Foo5; // (2) T is B* |
|---|
| 321 |
// (3) U is B |
|---|
| 322 |
------ |
|---|
| 323 |
|
|---|
| 324 |
<h2>Template Type Parameters</h2> |
|---|
| 325 |
|
|---|
| 326 |
$(GRAMMAR |
|---|
| 327 |
$(GNAME TemplateTypeParameter): |
|---|
| 328 |
$(I Identifier) |
|---|
| 329 |
$(I Identifier) $(I TemplateTypeParameterSpecialization) |
|---|
| 330 |
$(I Identifier) $(I TemplateTypeParameterDefault) |
|---|
| 331 |
$(I Identifier) $(I TemplateTypeParameterSpecialization) $(I TemplateTypeParameterDefault) |
|---|
| 332 |
|
|---|
| 333 |
$(GNAME TemplateTypeParameterSpecialization): |
|---|
| 334 |
$(B :) $(GLINK2 declaration, Type) |
|---|
| 335 |
|
|---|
| 336 |
$(GNAME TemplateTypeParameterDefault): |
|---|
| 337 |
$(B =) $(GLINK2 declaration, Type) |
|---|
| 338 |
) |
|---|
| 339 |
|
|---|
| 340 |
<h3>Specialization</h3> |
|---|
| 341 |
|
|---|
| 342 |
$(P Templates may be specialized for particular types of arguments |
|---|
| 343 |
by following the template parameter identifier with a : and the |
|---|
| 344 |
specialized type. |
|---|
| 345 |
For example: |
|---|
| 346 |
) |
|---|
| 347 |
|
|---|
| 348 |
------ |
|---|
| 349 |
template TFoo(T) { ... } // #1 |
|---|
| 350 |
template TFoo(T : T[]) { ... } // #2 |
|---|
| 351 |
template TFoo(T : char) { ... } // #3 |
|---|
| 352 |
template TFoo(T,U,V) { ... } // #4 |
|---|
| 353 |
|
|---|
| 354 |
alias TFoo!(int) foo1; // instantiates #1 |
|---|
| 355 |
alias TFoo!(double[]) foo2; // instantiates #2 with T being double |
|---|
| 356 |
alias TFoo!(char) foo3; // instantiates #3 |
|---|
| 357 |
alias TFoo!(char, int) fooe; // error, number of arguments mismatch |
|---|
| 358 |
alias TFoo!(char, int, int) foo4; // instantiates #4 |
|---|
| 359 |
------ |
|---|
| 360 |
|
|---|
| 361 |
$(P The template picked to instantiate is the one that is most specialized |
|---|
| 362 |
that fits the types of the $(I TemplateArgumentList). |
|---|
| 363 |
Determine which is more specialized is done the same way as the |
|---|
| 364 |
C++ partial ordering rules. |
|---|
| 365 |
If the result is ambiguous, it is an error. |
|---|
| 366 |
) |
|---|
| 367 |
|
|---|
| 368 |
|
|---|
| 369 |
$(V2 |
|---|
| 370 |
<h2>Template This Parameters</h2> |
|---|
| 371 |
|
|---|
| 372 |
$(GRAMMAR |
|---|
| 373 |
$(GNAME TemplateThisParameter): |
|---|
| 374 |
$(B this) $(I TemplateTypeParameter) |
|---|
| 375 |
) |
|---|
| 376 |
|
|---|
| 377 |
$(P $(I TemplateThisParameter)s are used in member function templates |
|---|
| 378 |
to pick up the type of the $(I this) reference. |
|---|
| 379 |
) |
|---|
| 380 |
--- |
|---|
| 381 |
import std.stdio; |
|---|
| 382 |
|
|---|
| 383 |
struct S |
|---|
| 384 |
{ |
|---|
| 385 |
const void foo(this T)(int i) |
|---|
| 386 |
{ |
|---|
| 387 |
writeln(typeid(T)); |
|---|
| 388 |
} |
|---|
| 389 |
} |
|---|
| 390 |
|
|---|
| 391 |
void main() |
|---|
| 392 |
{ |
|---|
| 393 |
const(S) s; |
|---|
| 394 |
(&s).foo(1); |
|---|
| 395 |
S s2; |
|---|
| 396 |
s2.foo(2); |
|---|
| 397 |
immutable(S) s3; |
|---|
| 398 |
s3.foo(3); |
|---|
| 399 |
} |
|---|
| 400 |
--- |
|---|
| 401 |
$(P Prints:) |
|---|
| 402 |
|
|---|
| 403 |
$(CONSOLE |
|---|
| 404 |
const(S) |
|---|
| 405 |
S |
|---|
| 406 |
immutable(S) |
|---|
| 407 |
) |
|---|
| 408 |
) |
|---|
| 409 |
|
|---|
| 410 |
<h2>Template Value Parameters</h2> |
|---|
| 411 |
|
|---|
| 412 |
$(GRAMMAR |
|---|
| 413 |
$(GNAME TemplateValueParameter): |
|---|
| 414 |
$(GLINK2 declaration, BasicType) $(GLINK2 declaration, Declarator) |
|---|
| 415 |
$(GLINK2 declaration, BasicType) $(GLINK2 declaration, Declarator) $(I TemplateValueParameterSpecialization) |
|---|
| 416 |
$(GLINK2 declaration, BasicType) $(GLINK2 declaration, Declarator) $(I TemplateValueParameterDefault) |
|---|
| 417 |
$(GLINK2 declaration, BasicType) $(GLINK2 declaration, Declarator) $(I TemplateValueParameterSpecialization) $(I TemplateValueParameterDefault) |
|---|
| 418 |
|
|---|
| 419 |
$(GNAME TemplateValueParameterSpecialization): |
|---|
| 420 |
$(B :) $(LINK2 expression.html#ConditionalExpression, $(I ConditionalExpression)) |
|---|
| 421 |
|
|---|
| 422 |
$(GNAME TemplateValueParameterDefault): |
|---|
| 423 |
$(V2 $(B = __FILE__) |
|---|
| 424 |
$(B = __LINE__)) |
|---|
| 425 |
$(B =) $(ASSIGNEXPRESSION) |
|---|
| 426 |
) |
|---|
| 427 |
|
|---|
| 428 |
$(V2 |
|---|
| 429 |
$(P The $(CODE __FILE__) and $(CODE __LINE__) expand to the source |
|---|
| 430 |
file name and line number at the point of instantiation.) |
|---|
| 431 |
) |
|---|
| 432 |
|
|---|
| 433 |
$(P Template value parameter types can be any type which can |
|---|
| 434 |
be statically initialized at compile time, and the value argument |
|---|
| 435 |
can be any expression which can be evaluated at compile time. |
|---|
| 436 |
This includes integers, floating point types, and strings. |
|---|
| 437 |
) |
|---|
| 438 |
|
|---|
| 439 |
----- |
|---|
| 440 |
template foo(string s) |
|---|
| 441 |
{ |
|---|
| 442 |
string bar() { return s ~ " betty"; } |
|---|
| 443 |
} |
|---|
| 444 |
|
|---|
| 445 |
void main() |
|---|
| 446 |
{ |
|---|
| 447 |
writefln("%s", foo!("hello").bar()); // prints: hello betty |
|---|
| 448 |
} |
|---|
| 449 |
----- |
|---|
| 450 |
|
|---|
| 451 |
$(P This example of template foo has a value parameter that |
|---|
| 452 |
is specialized for 10: |
|---|
| 453 |
) |
|---|
| 454 |
|
|---|
| 455 |
------ |
|---|
| 456 |
template foo(U : int, int T : 10) |
|---|
| 457 |
{ |
|---|
| 458 |
U x = T; |
|---|
| 459 |
} |
|---|
| 460 |
|
|---|
| 461 |
void main() |
|---|
| 462 |
{ |
|---|
| 463 |
assert(foo!(int, 10).x == 10); |
|---|
| 464 |
} |
|---|
| 465 |
------ |
|---|
| 466 |
|
|---|
| 467 |
|
|---|
| 468 |
<h2>$(LNAME2 aliasparameters, Template Alias Parameters)</h2> |
|---|
| 469 |
|
|---|
| 470 |
$(GRAMMAR |
|---|
| 471 |
$(GNAME TemplateAliasParameter): |
|---|
| 472 |
$(B alias) $(I Identifier) $(I TemplateAliasParameterSpecialization)$(OPT) $(I TemplateAliasParameterDefault)$(OPT) |
|---|
| 473 |
$(B alias) $(GLINK2 declaration, BasicType) $(GLINK2 declaration, Declarator) $(I TemplateAliasParameterSpecialization)$(OPT) $(I TemplateAliasParameterDefault)$(OPT) |
|---|
| 474 |
|
|---|
| 475 |
$(GNAME TemplateAliasParameterSpecialization): |
|---|
| 476 |
$(B :) $(GLINK2 declaration, Type) |
|---|
| 477 |
$(B :) $(GLINK2 expression, ConditionalExpression) |
|---|
| 478 |
|
|---|
| 479 |
$(GNAME TemplateAliasParameterDefault): |
|---|
| 480 |
$(B =) $(GLINK2 declaration, Type) |
|---|
| 481 |
$(B =) $(GLINK2 expression, ConditionalExpression) |
|---|
| 482 |
) |
|---|
| 483 |
|
|---|
| 484 |
$(P Alias parameters enable templates to be parameterized with |
|---|
| 485 |
any type of D symbol, including global names, local names, typedef |
|---|
| 486 |
names, module names, template names, and template instance names. |
|---|
| 487 |
$(V2 Literals can also be used as arguments to alias parameters.) |
|---|
| 488 |
) |
|---|
| 489 |
|
|---|
| 490 |
$(UL |
|---|
| 491 |
$(LI Global names |
|---|
| 492 |
|
|---|
| 493 |
------ |
|---|
| 494 |
int x; |
|---|
| 495 |
|
|---|
| 496 |
template Foo(alias X) |
|---|
| 497 |
{ |
|---|
| 498 |
static int* p = &X; |
|---|
| 499 |
} |
|---|
| 500 |
|
|---|
| 501 |
void test() |
|---|
| 502 |
{ |
|---|
| 503 |
alias Foo!(x) bar; |
|---|
| 504 |
*bar.p = 3; // set x to 3 |
|---|
| 505 |
static int y; |
|---|
| 506 |
alias Foo!(y) abc; |
|---|
| 507 |
*abc.p = 3; // set y to 3 |
|---|
| 508 |
} |
|---|
| 509 |
------ |
|---|
| 510 |
) |
|---|
| 511 |
|
|---|
| 512 |
$(LI Type names |
|---|
| 513 |
|
|---|
| 514 |
------ |
|---|
| 515 |
class Foo |
|---|
| 516 |
{ |
|---|
| 517 |
static int p; |
|---|
| 518 |
} |
|---|
| 519 |
|
|---|
| 520 |
template Bar(alias T) |
|---|
| 521 |
{ |
|---|
| 522 |
alias T.p q; |
|---|
| 523 |
} |
|---|
| 524 |
|
|---|
| 525 |
void test() |
|---|
| 526 |
{ |
|---|
| 527 |
alias Bar!(Foo) bar; |
|---|
| 528 |
bar.q = 3; // sets Foo.p to 3 |
|---|
| 529 |
} |
|---|
| 530 |
------ |
|---|
| 531 |
) |
|---|
| 532 |
|
|---|
| 533 |
$(LI Module names |
|---|
| 534 |
|
|---|
| 535 |
------ |
|---|
| 536 |
import std.string; |
|---|
| 537 |
|
|---|
| 538 |
template Foo(alias X) |
|---|
| 539 |
{ |
|---|
| 540 |
alias X.toString y; |
|---|
| 541 |
} |
|---|
| 542 |
|
|---|
| 543 |
void test() |
|---|
| 544 |
{ |
|---|
| 545 |
alias Foo!(std.string) bar; |
|---|
| 546 |
bar.y(3); // calls std.string.toString(3) |
|---|
| 547 |
} |
|---|
| 548 |
------ |
|---|
| 549 |
) |
|---|
| 550 |
|
|---|
| 551 |
$(LI Template names |
|---|
| 552 |
|
|---|
| 553 |
------ |
|---|
| 554 |
int x; |
|---|
| 555 |
|
|---|
| 556 |
template Foo(alias X) |
|---|
| 557 |
{ |
|---|
| 558 |
static int* p = &X; |
|---|
| 559 |
} |
|---|
| 560 |
|
|---|
| 561 |
template Bar(alias T) |
|---|
| 562 |
{ |
|---|
| 563 |
alias T!(x) abc; |
|---|
| 564 |
} |
|---|
| 565 |
|
|---|
| 566 |
void test() |
|---|
| 567 |
{ |
|---|
| 568 |
alias Bar!(Foo) bar; |
|---|
| 569 |
*bar.abc.p = 3; // sets x to 3 |
|---|
| 570 |
} |
|---|
| 571 |
------ |
|---|
| 572 |
) |
|---|
| 573 |
|
|---|
| 574 |
$(LI Template alias names |
|---|
| 575 |
|
|---|
| 576 |
------ |
|---|
| 577 |
int x; |
|---|
| 578 |
|
|---|
| 579 |
template Foo(alias X) |
|---|
| 580 |
{ |
|---|
| 581 |
static int* p = &X; |
|---|
| 582 |
} |
|---|
| 583 |
|
|---|
| 584 |
template Bar(alias T) |
|---|
| 585 |
{ |
|---|
| 586 |
alias T.p q; |
|---|
| 587 |
} |
|---|
| 588 |
|
|---|
| 589 |
void test() |
|---|
| 590 |
{ |
|---|
| 591 |
alias Foo!(x) foo; |
|---|
| 592 |
alias Bar!(foo) bar; |
|---|
| 593 |
*bar.q = 3; // sets x to 3 |
|---|
| 594 |
} |
|---|
| 595 |
------ |
|---|
| 596 |
) |
|---|
| 597 |
|
|---|
| 598 |
$(V2 $(LI Literals |
|---|
| 599 |
------ |
|---|
| 600 |
|
|---|
| 601 |
template Foo(alias X, alias Y) |
|---|
| 602 |
{ |
|---|
| 603 |
static int i = X; |
|---|
| 604 |
static string s = Y; |
|---|
| 605 |
} |
|---|
| 606 |
|
|---|
| 607 |
void test() |
|---|
| 608 |
{ |
|---|
| 609 |
alias Foo!(3, "bar") foo; |
|---|
| 610 |
writeln(foo.i, foo.s); // prints 3bar |
|---|
| 611 |
} |
|---|
| 612 |
------ |
|---|
| 613 |
)) |
|---|
| 614 |
) |
|---|
| 615 |
|
|---|
| 616 |
<h2>$(LNAME2 variadic-templates, Template Tuple Parameters)</h2> |
|---|
| 617 |
|
|---|
| 618 |
$(GRAMMAR |
|---|
| 619 |
$(GNAME TemplateTupleParameter): |
|---|
| 620 |
$(I Identifier) $(B ...) |
|---|
| 621 |
) |
|---|
| 622 |
|
|---|
| 623 |
$(P If the last template parameter in the $(I TemplateParameterList) |
|---|
| 624 |
is declared as a $(I TemplateTupleParameter), |
|---|
| 625 |
it is a match with any trailing template arguments. |
|---|
| 626 |
The sequence of arguments form a $(I Tuple). |
|---|
| 627 |
A $(I Tuple) is not a type, an expression, or a symbol. |
|---|
| 628 |
It is a sequence of any mix of types, expressions or symbols. |
|---|
| 629 |
) |
|---|
| 630 |
|
|---|
| 631 |
$(P A $(I Tuple) whose elements consist entirely of types is |
|---|
| 632 |
called a $(I TypeTuple). |
|---|
| 633 |
A $(I Tuple) whose elements consist entirely of expressions is |
|---|
| 634 |
called an $(I ExpressionTuple). |
|---|
| 635 |
) |
|---|
| 636 |
|
|---|
| 637 |
$(P A $(I Tuple) can be used as an argument list to instantiate |
|---|
| 638 |
another template, or as the list of parameters for a function. |
|---|
| 639 |
) |
|---|
| 640 |
|
|---|
| 641 |
--- |
|---|
| 642 |
template Print(A ...) |
|---|
| 643 |
{ |
|---|
| 644 |
void print() |
|---|
| 645 |
{ |
|---|
| 646 |
writefln("args are ", A); |
|---|
| 647 |
} |
|---|
| 648 |
} |
|---|
| 649 |
|
|---|
| 650 |
template Write(A ...) |
|---|
| 651 |
{ |
|---|
| 652 |
void write(A a) // A is a $(I TypeTuple) |
|---|
| 653 |
// a is an $(I ExpressionTuple) |
|---|
| 654 |
{ |
|---|
| 655 |
writefln("args are ", a); |
|---|
| 656 |
} |
|---|
| 657 |
} |
|---|
| 658 |
|
|---|
| 659 |
void main() |
|---|
| 660 |
{ |
|---|
| 661 |
Print!(1,'a',6.8).print(); // prints: args are 1a6.8 |
|---|
| 662 |
Write!(int, char, double).write(1, 'a', 6.8); // prints: args are 1a6.8 |
|---|
| 663 |
} |
|---|
| 664 |
--- |
|---|
| 665 |
|
|---|
| 666 |
$(P Template tuples can be deduced from the types of |
|---|
| 667 |
the trailing parameters |
|---|
| 668 |
of an implicitly instantiated function template:) |
|---|
| 669 |
|
|---|
| 670 |
--- |
|---|
| 671 |
template Foo(T, R...) |
|---|
| 672 |
{ |
|---|
| 673 |
void Foo(T t, R r) |
|---|
| 674 |
{ |
|---|
| 675 |
writefln(t); |
|---|
| 676 |
static if (r.length) // if more arguments |
|---|
| 677 |
Foo(r); // do the rest of the arguments |
|---|
| 678 |
} |
|---|
| 679 |
} |
|---|
| 680 |
|
|---|
| 681 |
void main() |
|---|
| 682 |
{ |
|---|
| 683 |
Foo(1, 'a', 6.8); |
|---|
| 684 |
} |
|---|
| 685 |
--- |
|---|
| 686 |
$(P prints:) |
|---|
| 687 |
|
|---|
| 688 |
$(CONSOLE |
|---|
| 689 |
1 |
|---|
| 690 |
a |
|---|
| 691 |
6.8 |
|---|
| 692 |
) |
|---|
| 693 |
$(P The tuple can also be deduced from the type of a delegate |
|---|
| 694 |
or function parameter list passed as a function argument:) |
|---|
| 695 |
|
|---|
| 696 |
---- |
|---|
| 697 |
import std.stdio; |
|---|
| 698 |
|
|---|
| 699 |
/* R is return type |
|---|
| 700 |
* A is first argument type |
|---|
| 701 |
* U is $(I TypeTuple) of rest of argument types |
|---|
| 702 |
*/ |
|---|
| 703 |
R delegate(U) Curry(R, A, U...)(R delegate(A, U) dg, A arg) |
|---|
| 704 |
{ |
|---|
| 705 |
struct Foo |
|---|
| 706 |
{ |
|---|
| 707 |
typeof(dg) dg_m; |
|---|
| 708 |
typeof(arg) arg_m; |
|---|
| 709 |
|
|---|
| 710 |
R bar(U u) |
|---|
| 711 |
{ |
|---|
| 712 |
return dg_m(arg_m, u); |
|---|
| 713 |
} |
|---|
| 714 |
} |
|---|
| 715 |
|
|---|
| 716 |
Foo* f = new Foo; |
|---|
| 717 |
f.dg_m = dg; |
|---|
| 718 |
f.arg_m = arg; |
|---|
| 719 |
return &f.bar; |
|---|
| 720 |
} |
|---|
| 721 |
|
|---|
| 722 |
void main() |
|---|
| 723 |
{ |
|---|
| 724 |
int plus(int x, int y, int z) |
|---|
| 725 |
{ |
|---|
| 726 |
return x + y + z; |
|---|
| 727 |
} |
|---|
| 728 |
|
|---|
| 729 |
auto plus_two = Curry(&plus, 2); |
|---|
| 730 |
writefln("%d", plus_two(6, 8)); // prints 16 |
|---|
| 731 |
} |
|---|
| 732 |
---- |
|---|
| 733 |
|
|---|
| 734 |
$(P The number of elements in a $(I Tuple) can be retrieved with |
|---|
| 735 |
the $(B .length) property. The $(I n)th element can be retrieved |
|---|
| 736 |
by indexing the $(I Tuple) with [$(I n)], |
|---|
| 737 |
and sub tuples can be created |
|---|
| 738 |
with the slicing syntax. |
|---|
| 739 |
) |
|---|
| 740 |
|
|---|
| 741 |
$(P $(I Tuple)s are static compile time entities, there is no way |
|---|
| 742 |
to dynamically change, add, or remove elements.) |
|---|
| 743 |
|
|---|
| 744 |
$(P If both a template with a tuple parameter and a template |
|---|
| 745 |
without a tuple parameter exactly match a template instantiation, |
|---|
| 746 |
the template without a $(I TemplateTupleParameter) is selected.) |
|---|
| 747 |
|
|---|
| 748 |
<h2>Template Parameter Default Values</h2> |
|---|
| 749 |
|
|---|
| 750 |
$(P Trailing template parameters can be given default values: |
|---|
| 751 |
) |
|---|
| 752 |
|
|---|
| 753 |
------ |
|---|
| 754 |
template Foo(T, U = int) { ... } |
|---|
| 755 |
Foo!(uint,long); // instantiate Foo with T as uint, and U as long |
|---|
| 756 |
Foo!(uint); // instantiate Foo with T as uint, and U as int |
|---|
| 757 |
|
|---|
| 758 |
template Foo(T, U = T*) { ... } |
|---|
| 759 |
Foo!(uint); // instantiate Foo with T as uint, and U as uint* |
|---|
| 760 |
------ |
|---|
| 761 |
|
|---|
| 762 |
<h2>Implicit Template Properties</h2> |
|---|
| 763 |
|
|---|
| 764 |
$(P If a template has exactly one member in it, and the name of that |
|---|
| 765 |
member is the same as the template name, that member is assumed |
|---|
| 766 |
to be referred to in a template instantiation: |
|---|
| 767 |
) |
|---|
| 768 |
|
|---|
| 769 |
------ |
|---|
| 770 |
template $(B Foo)(T) |
|---|
| 771 |
{ |
|---|
| 772 |
T $(B Foo); // declare variable Foo of type T |
|---|
| 773 |
} |
|---|
| 774 |
|
|---|
| 775 |
void test() |
|---|
| 776 |
{ |
|---|
| 777 |
$(B Foo)!(int) = 6; // instead of Foo!(int).Foo |
|---|
| 778 |
} |
|---|
| 779 |
------ |
|---|
| 780 |
|
|---|
| 781 |
<h2>Template Constructors</h2> |
|---|
| 782 |
|
|---|
| 783 |
$(GRAMMAR |
|---|
| 784 |
$(GNAME TemplatedConstructor): |
|---|
| 785 |
$(B this) $(B $(LPAREN)) $(GLINK2 template, TemplateParameterList) $(B $(RPAREN)) $(GLINK2 declaration, Parameters) $(GLINK Constraint)$(OPT) $(GLINK2 function, FunctionBody) |
|---|
| 786 |
) |
|---|
| 787 |
|
|---|
| 788 |
$(P Templates can be used to form constructors for classes$(V2 and structs). |
|---|
| 789 |
) |
|---|
| 790 |
|
|---|
| 791 |
<h2>Class Templates</h2> |
|---|
| 792 |
|
|---|
| 793 |
$(GRAMMAR |
|---|
| 794 |
$(GNAME ClassTemplateDeclaration): |
|---|
| 795 |
$(B class) $(I Identifier) $(B $(LPAREN)) $(GLINK TemplateParameterList) $(B $(RPAREN)) $(GLINK Constraint)$(OPT) $(GLINK2 class, BaseClassList) $(GLINK2 class, ClassBody) |
|---|
| 796 |
) |
|---|
| 797 |
|
|---|
| 798 |
$(P If a template declares exactly one member, and that member is a class |
|---|
| 799 |
with the same name as the template: |
|---|
| 800 |
) |
|---|
| 801 |
|
|---|
| 802 |
------ |
|---|
| 803 |
template $(B Bar)(T) |
|---|
| 804 |
{ |
|---|
| 805 |
class $(B Bar) |
|---|
| 806 |
{ |
|---|
| 807 |
T member; |
|---|
| 808 |
} |
|---|
| 809 |
} |
|---|
| 810 |
------ |
|---|
| 811 |
|
|---|
| 812 |
$(P then the semantic equivalent, called a $(I ClassTemplateDeclaration) |
|---|
| 813 |
can be written as: |
|---|
| 814 |
) |
|---|
| 815 |
|
|---|
| 816 |
------ |
|---|
| 817 |
class $(B Bar)(T) |
|---|
| 818 |
{ |
|---|
| 819 |
T member; |
|---|
| 820 |
} |
|---|
| 821 |
------ |
|---|
| 822 |
|
|---|
| 823 |
<h2>Struct, Union, and Interface Templates</h2> |
|---|
| 824 |
|
|---|
| 825 |
$(GRAMMAR |
|---|
| 826 |
$(GNAME StructTemplateDeclaration): |
|---|
| 827 |
$(B struct) $(I Identifier) $(B $(LPAREN)) $(GLINK TemplateParameterList) $(B $(RPAREN)) $(V2 $(GLINK Constraint)$(SUB $(I opt))) $(LINK2 struct.html#StructBody, $(I StructBody)) |
|---|
| 828 |
|
|---|
| 829 |
$(GNAME UnionTemplateDeclaration): |
|---|
| 830 |
$(B union) $(I Identifier) $(B $(LPAREN)) $(GLINK TemplateParameterList) $(B $(RPAREN)) $(V2 $(GLINK Constraint)$(SUB $(I opt))) $(LINK2 struct.html#StructBody, $(I StructBody)) |
|---|
| 831 |
|
|---|
| 832 |
$(GNAME InterfaceTemplateDeclaration): |
|---|
| 833 |
$(B interface) $(I Identifier) $(B $(LPAREN)) $(GLINK TemplateParameterList) $(B $(RPAREN)) $(V2 $(GLINK Constraint)$(SUB $(I opt))) $(LINK2 interface.html#BaseInterfaceList, $(I BaseInterfaceList)) $(LINK2 interface.html#InterfaceBody, $(I InterfaceBody)) |
|---|
| 834 |
) |
|---|
| 835 |
|
|---|
| 836 |
$(P Analogously to class templates, struct, union and interfaces |
|---|
| 837 |
can be transformed into templates by supplying a template parameter list. |
|---|
| 838 |
) |
|---|
| 839 |
|
|---|
| 840 |
<h2>$(LNAME2 function-templates, Function Templates)</h2> |
|---|
| 841 |
|
|---|
| 842 |
$(P If a template declares exactly one member, and that member is a function |
|---|
| 843 |
with the same name as the template, it is a function template declaration. |
|---|
| 844 |
Alternatively, a function template declaration is a function declaration |
|---|
| 845 |
with a $(GLINK TemplateParameterList) immediately preceding the |
|---|
| 846 |
$(LINK2 declaration.html#Parameters, $(I Parameters)). |
|---|
| 847 |
) |
|---|
| 848 |
|
|---|
| 849 |
$(P A function template to compute the square of type $(I T) is: |
|---|
| 850 |
) |
|---|
| 851 |
------ |
|---|
| 852 |
T $(B Square)(T)(T t) |
|---|
| 853 |
{ |
|---|
| 854 |
return t * t; |
|---|
| 855 |
} |
|---|
| 856 |
------ |
|---|
| 857 |
|
|---|
| 858 |
$(P Function templates can be explicitly instantiated with a |
|---|
| 859 |
!($(I TemplateArgumentList)): |
|---|
| 860 |
) |
|---|
| 861 |
|
|---|
| 862 |
---- |
|---|
| 863 |
writefln("The square of %s is %s", 3, Square!(int)(3)); |
|---|
| 864 |
---- |
|---|
| 865 |
|
|---|
| 866 |
$(P or implicitly, where the $(I TemplateArgumentList) is deduced |
|---|
| 867 |
from the types of the function arguments: |
|---|
| 868 |
) |
|---|
| 869 |
|
|---|
| 870 |
---- |
|---|
| 871 |
writefln("The square of %s is %s", 3, Square(3)); // T is deduced to be int |
|---|
| 872 |
---- |
|---|
| 873 |
|
|---|
| 874 |
$(P If there are fewer arguments supplied in the $(I TemplateArgumentList) |
|---|
| 875 |
than parameters in the $(I TemplateParameterList), the arguments fulfill |
|---|
| 876 |
parameters from left to right, and the rest of the parameters are then deduced |
|---|
| 877 |
from the function arguments. |
|---|
| 878 |
) |
|---|
| 879 |
|
|---|
| 880 |
$(P Function template type parameters that are to be implicitly |
|---|
| 881 |
deduced may not have specializations: |
|---|
| 882 |
) |
|---|
| 883 |
|
|---|
| 884 |
------ |
|---|
| 885 |
void $(B Foo)(T : T*)(T t) { ... } |
|---|
| 886 |
|
|---|
| 887 |
int x,y; |
|---|
| 888 |
Foo!(int*)(x); // ok, T is not deduced from function argument |
|---|
| 889 |
Foo(&y); // error, T has specialization |
|---|
| 890 |
------ |
|---|
| 891 |
|
|---|
| 892 |
$(P Template arguments not implicitly deduced can have default values: |
|---|
| 893 |
) |
|---|
| 894 |
|
|---|
| 895 |
------ |
|---|
| 896 |
void $(B Foo)(T, U=T*)(T t) { U p; ... } |
|---|
| 897 |
|
|---|
| 898 |
int x; |
|---|
| 899 |
Foo(&x); // T is int, U is int* |
|---|
| 900 |
------ |
|---|
| 901 |
|
|---|
| 902 |
$(V2 $(P Function templates can have their return types deduced based |
|---|
| 903 |
on the first |
|---|
| 904 |
$(LINK2 statement.html#ReturnStatement, $(I ReturnStatement)) |
|---|
| 905 |
in the function: |
|---|
| 906 |
) |
|---|
| 907 |
|
|---|
| 908 |
--- |
|---|
| 909 |
auto $(B Square)(T)(T t) |
|---|
| 910 |
{ |
|---|
| 911 |
return t * t; |
|---|
| 912 |
} |
|---|
| 913 |
--- |
|---|
| 914 |
$(P If there is more than one return statement, then the |
|---|
| 915 |
types of the return statement expressions must match. |
|---|
| 916 |
If there are no return statements, then the return type of the |
|---|
| 917 |
function template is $(CODE void). |
|---|
| 918 |
) |
|---|
| 919 |
) |
|---|
| 920 |
|
|---|
| 921 |
<h3>$(LNAME2 auto-ref-parameters, Function Templates with Auto Ref Parameters)</h3> |
|---|
| 922 |
|
|---|
| 923 |
$(P An auto ref function template parameter becomes a ref parameter |
|---|
| 924 |
if its corresponding argument is an lvalue, otherwise it becomes |
|---|
| 925 |
a value parameter: |
|---|
| 926 |
) |
|---|
| 927 |
|
|---|
| 928 |
--- |
|---|
| 929 |
int foo(T...)(auto ref T x) |
|---|
| 930 |
{ int result; |
|---|
| 931 |
|
|---|
| 932 |
foreach (i, v; x) |
|---|
| 933 |
{ |
|---|
| 934 |
if (v == 10) |
|---|
| 935 |
assert(__traits(isRef, x[i])); |
|---|
| 936 |
else |
|---|
| 937 |
assert(!__traits(isRef, x[i])); |
|---|
| 938 |
result += v; |
|---|
| 939 |
} |
|---|
| 940 |
return result; |
|---|
| 941 |
} |
|---|
| 942 |
|
|---|
| 943 |
void main() |
|---|
| 944 |
{ int y = 10; |
|---|
| 945 |
int r; |
|---|
| 946 |
r = foo(8); // returns 8 |
|---|
| 947 |
r = foo(y); // returns 10 |
|---|
| 948 |
r = foo(3, 4, y); // returns 17 |
|---|
| 949 |
r = foo(4, 5, y); // returns 19 |
|---|
| 950 |
r = foo(y, 6, y); // returns 26 |
|---|
| 951 |
} |
|---|
| 952 |
--- |
|---|
| 953 |
|
|---|
| 954 |
$(P Auto ref parameters can be combined with auto ref return |
|---|
| 955 |
attributes: |
|---|
| 956 |
) |
|---|
| 957 |
|
|---|
| 958 |
--- |
|---|
| 959 |
auto ref min(T, U)(auto ref T lhs, auto ref U rhs) |
|---|
| 960 |
{ |
|---|
| 961 |
return lhs > rhs ? rhs : lhs; |
|---|
| 962 |
} |
|---|
| 963 |
|
|---|
| 964 |
void main() |
|---|
| 965 |
{ int x = 7, y = 8; |
|---|
| 966 |
int i; |
|---|
| 967 |
|
|---|
| 968 |
i = min(4, 3); // returns 3 |
|---|
| 969 |
i = min(x, y); // returns 7 |
|---|
| 970 |
min(x, y) = 10; // sets x to 10 |
|---|
| 971 |
static assert(!__traits(compiles, min(3, y) = 10)); |
|---|
| 972 |
static assert(!__traits(compiles, min(y, 3) = 10)); |
|---|
| 973 |
} |
|---|
| 974 |
--- |
|---|
| 975 |
|
|---|
| 976 |
<h2>Recursive Templates</h2> |
|---|
| 977 |
|
|---|
| 978 |
$(P Template features can be combined to produce some interesting |
|---|
| 979 |
effects, such as compile time evaluation of non-trivial functions. |
|---|
| 980 |
For example, a factorial template can be written: |
|---|
| 981 |
) |
|---|
| 982 |
|
|---|
| 983 |
------ |
|---|
| 984 |
template factorial(int n : 1) |
|---|
| 985 |
{ |
|---|
| 986 |
enum { factorial = 1 } |
|---|
| 987 |
} |
|---|
| 988 |
|
|---|
| 989 |
template factorial(int n) |
|---|
| 990 |
{ |
|---|
| 991 |
enum { factorial = n* factorial!(n-1) } |
|---|
| 992 |
} |
|---|
| 993 |
|
|---|
| 994 |
void test() |
|---|
| 995 |
{ |
|---|
| 996 |
writefln("%s", factorial!(4)); // prints 24 |
|---|
| 997 |
} |
|---|
| 998 |
------ |
|---|
| 999 |
|
|---|
| 1000 |
$(V2 |
|---|
| 1001 |
<h2>Template Constraints</h2> |
|---|
| 1002 |
|
|---|
| 1003 |
--- |
|---|
| 1004 |
$(GNAME Constraint): |
|---|
| 1005 |
$(B if) $(B $(LPAREN)) $(I ConstraintExpression) $(B $(RPAREN)) |
|---|
| 1006 |
|
|---|
| 1007 |
$(I ConstraintExpression): |
|---|
| 1008 |
$(I $(GLINK2 expression, Expression)) |
|---|
| 1009 |
--- |
|---|
| 1010 |
|
|---|
| 1011 |
$(P $(I Constraint)s are used to impose additional constraints |
|---|
| 1012 |
on matching arguments to a template beyond what is possible |
|---|
| 1013 |
in the $(GLINK TemplateParameterList). |
|---|
| 1014 |
The $(I ConstraintExpression) is computed at compile time |
|---|
| 1015 |
and returns a result that is converted to a boolean value. |
|---|
| 1016 |
If that value is true, then the template is matched, |
|---|
| 1017 |
otherwise the template is not matched. |
|---|
| 1018 |
) |
|---|
| 1019 |
|
|---|
| 1020 |
$(P For example, the following function template only |
|---|
| 1021 |
matches with odd values of $(CODE N): |
|---|
| 1022 |
) |
|---|
| 1023 |
|
|---|
| 1024 |
--- |
|---|
| 1025 |
void foo(int N)() |
|---|
| 1026 |
if (N & 1) |
|---|
| 1027 |
{ |
|---|
| 1028 |
... |
|---|
| 1029 |
} |
|---|
| 1030 |
... |
|---|
| 1031 |
foo!(3)(); // ok, matches |
|---|
| 1032 |
foo!(4)(); // error, no match |
|---|
| 1033 |
--- |
|---|
| 1034 |
) |
|---|
| 1035 |
|
|---|
| 1036 |
<h2>Limitations</h2> |
|---|
| 1037 |
|
|---|
| 1038 |
$(P Templates cannot be used to add non-static members or |
|---|
| 1039 |
virtual functions to classes. |
|---|
| 1040 |
For example: |
|---|
| 1041 |
) |
|---|
| 1042 |
|
|---|
| 1043 |
------ |
|---|
| 1044 |
class Foo |
|---|
| 1045 |
{ |
|---|
| 1046 |
template TBar(T) |
|---|
| 1047 |
{ |
|---|
| 1048 |
T xx; // becomes a static member of Foo |
|---|
| 1049 |
int func(T) { ... } // non-virtual |
|---|
| 1050 |
|
|---|
| 1051 |
static T yy; // Ok |
|---|
| 1052 |
static int func(T t, int y) { ... } // Ok |
|---|
| 1053 |
} |
|---|
| 1054 |
} |
|---|
| 1055 |
------ |
|---|
| 1056 |
|
|---|
| 1057 |
$(P Templates cannot be declared inside functions. |
|---|
| 1058 |
) |
|---|
| 1059 |
|
|---|
| 1060 |
$(P Templates cannot add functions to interfaces:) |
|---|
| 1061 |
--- |
|---|
| 1062 |
interface TestInterface { void tpl(T)(); } // error |
|---|
| 1063 |
--- |
|---|
| 1064 |
) |
|---|
| 1065 |
|
|---|
| 1066 |
Macros: |
|---|
| 1067 |
TITLE=Templates |
|---|
| 1068 |
WIKI=Template |
|---|
| 1069 |
GLINK=$(LINK2 #$0, $(I $0)) |
|---|
| 1070 |
GNAME=<a name=$0>$(I $0)</a> |
|---|
| 1071 |
DOLLAR=$ |
|---|
| 1072 |
FOO= |
|---|