[Home]
[Search]
[D]
TemplateDeclaration:
template TemplateIdentifier ( TemplateParameterList )
{ DeclDefs }
TemplateIdentifier:
Identifier
TemplateParameterList
TemplateParameter
TemplateParameter , TemplateParameterList
TemplateParameter:
TypeParameter
ValueParameter
TypeParameter:
Identifier
Identifier : Type
ValueParameter:
Declaration
Declaration : AssignExpression
The body of the TemplateDeclaration must be syntactically correct
even if never instantiated. Semantic analysis is not done until
instantiated. A template forms its own scope, and the template
body can contain classes, structs, types, enums, variables,
functions, and other templates.
Template parameters can be either types or values. Value parameters must be of an integral type, and specializations for them must resolve to an integral constant.
Templates are instantiated with:
TemplateInstance: instance TemplateIdentifer ( TemplateArgumentList ) TemplateAliasDeclaration: TemplateInstance AliasIdentifier; AliasIdentifier: Identifier TemplateArgumentList: TemplateArgument TemplateArgument , TemplateArgumentList TemplateArgument: Type AssignExpressionOnce instantiated, the declarations inside the template, called the template members, are in the scope of the AliasIdentifier:
template TFoo(T) { alias T* t; }
instance TFoo(int) abc;
...
abc.t x; // declare x to be of type int
Template members can also
be accessed directly from the TemplateInstance:
template TFoo(T) { alias T* t; }
instance TFoo(int).t x; // declare x to be of type int
Multiple instantiations of a TemplateDeclaration with the same
TemplateParameterList all will refer to the same instantiation.
For example:
template TFoo(T) { T f; }
instance TFoo(int) a;
instance TFoo(int) b;
...
a.f = 3;
assert(b.f == 3); // a and b refer to the same instance of TFoo
This is true even if the TemplateInstances are done in
different modules.
If multiple templates with the same TemplateIdentifier are declared, they are distinct if they have a different number of arguments or are differently specialized.
For example, a simple generic copy template would be:
template TCopy(T)
{
void copy(out T to, T from)
{
to = from;
}
}
To use the template, it must first be instantiated with a specific
type:
instance TCopy(int) copyint;And then the instance can be called:
int i; copyint.copy(i, 3);
For example:
-------- module a ---------
template TFoo(T) { void bar() { func(); } }
-------- module b ---------
import a;
void func() { }
instance TFoo(int) f; // error: func not defined in module a
and:
-------- module a ---------
template TFoo(T) { void bar() { func(1); } }
void func(double d) { }
-------- module b ---------
import a;
void func(int i) { }
instance TFoo(int) f;
...
f.bar(); // will call a.func(double)
For each template parameter, the following rules are applied in order until a type is deduced for each parameter:
template TFoo(T) { }
instance TFoo(int) Foo1; // (1) T is deduced to be int
instance TFoo(char*) Foo2; // (1) T is deduced to be char*
template TFoo(T : T*) { }
instance TFoo(char*) Foo3; // (2) T is deduced to be char
template TBar(D, U : D[]) { }
instance TBar(int, int[]) Bar1; // (2) D is deduced to be int, U is int[]
instance TBar(char, int[]) Bar2; // (4) error, D is both char and int
template TBar(D : E*, E) { }
instance TBar(int*, int); // (1) E is int
// (3) D is int*
When considering matches, a class is
considered to be a match for any super classes or interfaces:
class A { }
class B : A { }
template TFoo(T : A) { }
instance TFoo(B); // (3) T is B
template TBar(T : U*, U : A) { }
instance TBar(B*, B); // (2) T is B*
// (3) U is B
template foo(U : int, int T : 10)
{
U x = T;
}
void main()
{
assert(instance foo(int, 10).x == 10);
}
template TFoo(T) { ... } // #1
template TFoo(T : T[]) { ... } // #2
template TFoo(T : char) { ... } // #3
template TFoo(T,U,V) { ... } // #4
instance TFoo(int) foo1; // instantiates #1
instance TFoo(double[]) foo2; // instantiates #2 with T being double
instance TFoo(char) foo3; // instantiates #3
instance TFoo(char, int) fooe; // error, number of arguments mismatch
instance TFoo(char, int, int) foo4; // instantiates #4
The template picked to instantiate is the one that is most specialized
that fits the types of the TemplateArgumentList.
Determine which is more specialized is done the same way as the
C++ partial ordering rules.
If the result is ambiguous, it is an error.
class Foo
{
template TBar(T)
{
T xx; // Error
int func(T) { ... } // Error
static T yy; // Ok
static int func(T t, int y) { ... } // Ok
}
}
Templates cannot be declared inside functions.