Si nunca se ha tenido contacto con la metaprogramación mediante plantillas (template meta programming en inglés) en C++, se puede sentir alivio gracias a las herramientas que ofrece D para hacer la vida más fácil. La metaprogramación mediante plantillas es una técnica que permite la toma de decisiones dependiendo del tipo de plantilla, permitiendo así hacer que los tipos de datos genéricos sean aún más flexibles basándose en el tipo de dato con el que van a ser instanciados.
static if
e is
Igual que un if
normal, un static if
compila un bloque de código de forma
condicional según una condición que pueda ser evaluada en tiempo de compilación:
static if(is(T == int))
writeln("T es un int");
static if (is(typeof(x) : int))
writeln("La variable x se convierte de forma implícita a int");
La expresión is
es una expresión
genérica de ayuda que evalúa condiciones en tiempo de compilación.
static if(is(T == int)) { // T es un parámetro de plantilla
int x = 10;
}
Las llaves ({}
) se omiten si la condición es verdadera (true
), es decir,
no se crea un ámbito nuevo. Si se quiere crear un ámbito nuevo, hay que
hacerlo de forma explítica declarando un bloque mediante { {
y } }
.
La expresión static if
se puede usar en cualquier parte del código: en
funciones, en el ámbito global o dentro de definiciones de tipos.
mixin template
En cualquier sitio donde se vea código repetitivo (boiler plate en inglés),
mixin template
es tu amigo:
mixin template Foo(T) {
T foo;
}
...
mixin Foo!int; // `int foo` disponible a partir de aquí
La expresión mixin template
puede contener cualquier número de expresiones
complejas que son insertadas en el punto donde se instancia la plantilla. Con
esto se puede decir adiós a las directivas del preprocesador de C.
Una plantilla se puede definir con cualquier número de restricciones. Estas restricciones fuerzan qué propiedades tiene que tener un tipo de dato:
void foo(T)(T value)
if (is(T : int)) { // foo!T es sólo válida si T
// se puede convertir a `int`.
}
Las restricciones se pueden combinar mediante expresiones booleanas e, incluso,
pueden contener llamadas a otras funciones que puedan ser evaluadas en tiempo
de compilación. Por ejemplo, la función std.range.primitives.isRandomAccessRange
comprueba si un tipo de dato es un rango que soporta el operador []
.