D programming Language



Download 1.66 Mb.
Page22/47
Date08.01.2017
Size1.66 Mb.
#7507
1   ...   18   19   20   21   22   23   24   25   ...   47

Future Directions


Likely many more operators will become overloadable. But the operators ., &&, ||, ?:, and a

Templates


Templates are D's approach to generic programming. Templates are defined with a TemplateDeclaration:

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

AssignExpression

Once 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);




Instantiation Scope


TemplateInstantances are always performed in the scope of where the TemplateDeclaration is declared, with the addition of the template parameters being declared as aliases for their deduced types.

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)




Argument Deduction


The types of template parameters are deduced for a particular template instantiation by comparing the template argument with the corresponding template parameter.

For each template parameter, the following rules are applied in order until a type is deduced for each parameter:



  1. If there is no type specialization for the parameter, the type of the parameter is set to the template argument.

  2. If the type specialization is dependent on a type parameter, the type of that parameter is set to be the corresponding part of the type argument.

  3. If after all the type arguments are examined there are any type parameters left with no type assigned, they are assigned types corresponding to the template argument in the same position in the TemplateArgumentList.

  4. If applying the above rules does not result in exactly one type for each template parameter, then it is an error.

For example:

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




Download 1.66 Mb.

Share with your friends:
1   ...   18   19   20   21   22   23   24   25   ...   47




The database is protected by copyright ©ininet.org 2024
send message

    Main page