D-ben a generikus programozást a template-ek segítik. Egy template-et egy TemplateDeclaration-nel definiálhatunk.
TemplateDeclaration:
template TemplateIdentifier ( TemplateParameterList )
{ DeclDefs }
TemplateIdentifier:
Identifier
TemplateParameterList
TemplateParameter
TemplateParameter , TemplateParameterList
TemplateParameter:
TypeParameter
ValueParameter
AliasParameter
TemplateTypeParameter:
Identifier
Identifier TemplateTypeParameterSpecialization
Identifier TemplateTypeParameterDefault
Identifier TemplateTypeParameterSpecialization
TemplateTypeParameterDefault
TemplateTypeParameterSpecialization:
: Type
TemplateTypeParameterDefault:
= Type
TemplateValueParameter:
Declaration
Declaration TemplateValueParameterSpecialization
Declaration TemplateValueParameterDefault
Declaration TemplateValueParameterSpecialization
TemplateValueParameterDefault
TemplateValueParameterSpecialization:
: ConditionalExpression
TemplateValueParameterDefault:
= ConditionalExpression
TemplateAliasParameter:
alias Identifier
alias Identifier TemplateAliasParameterDefault
TemplateAliasParameterDefault:
= Type
A templatedeklaráció szintaktikusan helyes kell legyen, még akkor is, ha az illető template-et sohasem példányosítják A szemantikai elemzés csak példányosításkor történik meg. Egy template-nek saját scope-ja van, amely tartalmazhat osztályokat, struct-okat, típusokat, felsorolási típusokat, változókat, függvényeket, ill. más template-eket. Template paraméter lehet típus, érték, vagy szimbólum. A típusargumentum tetszőleges típus lehet. Az értékargumentumok csak beépített típusúak lehetnek, és csak egész értékre specializálhatunk. Szimbólum bármilyen nem-lokális szimbólum.
Lehetőség van a template-ek paraméterek szerinti specializálására, illetve default argumentum érték megadására.
A template példányositás a következő:
TemplateInstance:
TemplateIdentifer !( TemplateArgumentList )
TemplateArgumentList:
TemplateArgument
TemplateArgument , TemplateArgumentList
TemplateArgument:
Type
AssignExpression
Symbol
A példányosítás után a template-ben található deklarációk (ún. template memberek) a létrejött példány scope-jában vannak.
A létrejött példánynak álnév adható.
Adott template deklaráció többszöri példányosítása ugyanazzal a paraméterlistával mindig ugyanarra a példányra fog hivatkozni.
Ez akkor is igaz, ha a példányosítások különböző modulokban történnek. Ha azonos néven, de különböző hosszú paraméterlistával, vagy más paraméter specializációval deklarálunk template-eket, akkor azok különbözőek. Pl egy általános másoló template a következő:
Hogy egy template-et használni tudjunk, előbb példányosításra van szükség.
A példányosítás mindig abban a scope-ban történik, melyben a template-et deklarálták. A template paraméterek álnévként szolgálnak az argumentumdedukció eredményeként kapott típusra.
Pl:
Pl 2:
A paraméter specializációk és default értékek a deklaráció scope-jában értékelődnek ki.
A template paraméterek típusának kikövetkeztetése egy adott példányosítás során (=dedukció) úgy történik, hogy az argumentumot a megfelelő helyen levő paraméterrel hasonlítjuk össze.
Az alábbi példában foo “érték típusú” paramétere, mely most 10-re van specializálva.
A template-ek specializálhatók különféle argumentumokra oly módon, hogy a paraméter neve mögé egy kettőspontot teszünk, majd leírjuk a kívánt típust, amire specializálni szeretnénk.
Mindig a legspecializáltabb template példányosul, ezt a C++ döntési szabályaihoz hasonlóan dől el. Ha több template is megfelel, az hibát jelent.
Egy template paraméternek lehet default értéke:
Ha egy template-nek pontosan egy tagja van, és annak neve megegyezik a template-ével, akkor egy adott példányosításkor feltételezzük, hogy arra történik hivatkozás:
ClassTemplateDeclaration:
class Identifier ( TemplateParameterList ) [SuperClass {, InterfaceClass }] ClassBody
Ha egy template-nek pontosan egy tagja van, mely egy class, és melynek neve megegyezik a template-ével:
akkor ez írható a következő formában:
A template-ek tulajdonságait jól kihasználva érdekes hatást érhetünk el, mint például amilyen egy nem-triviális függvény fordítási idejű kiértékelése, Pl egy faktoriális template a következő lehet:
Egy template nem használható arra, hogy nem-statikus tagokat vegyünk fel egy osztályba vagy függvénybe. Pl.
Ezen kívül egy template nem deklarálható függvényeken belül.
A D különböző nyelvi elemekkel támogatja a template metaprogramozást. Segítségükkel nem csak hatékonyab metaprogramokat írhatunk, de nagyságrendekkel olvashatóbb kódot is kapunk. D-ben két szerkezetet is kapunk arra, hogy bizonyos kifejezéseket fordítási időben értékeljünk ki. Ezek pedig az is és a static_if. Az is(typeof(expr)) kifejezést igazat ad vissza, ha az expr egy érvényes kifejezés, ellenkező esetben pedig hamist, anélkül, hogy a fordítás leállna. A static_if szerkezet pedig egy logikai kifejezést értekel ki fordítási időben, ha ez megtehető. Csupán ez a két funkció megfelezi a template metaprogramok komplexitását.
A static_if kifejezés használata nélkül a faktoriális metaprogram a következőképpen néz ki D nyelven:
Ezzel szemben static_if használatával a kód meglepően hasonlít a futási idejű változathoz:
Érdemes megemlíteni még az std.traits könyvtárat, amely arra hivatott, hogy kifejezésekből és szimbólumokból fordítási időben vonhassunk ki értékes információkat. Ilyen lehet például, hogy egy template paraméter szám-e, pointer-e, használható-e függvényként, és még hosszú a sor.