Hermosos templates en C++ (parte I)

No haré una exposición extensa sobre los templates en C++, puesto que hay de sobra información en Internet; pero sí me gustaría publicar unos cuantos que estoy utilizando en estos momentos para un mock-up de una biblioteca de NURBS. Su fin no es la eficiencia sino la versatilidad, por lo que estoy prefiriendo ciertos patrones de diseño sobre otros con tal de facilitar la generalización y rápida prueba del software.

Por ejemplo, la típica clase de punto n-dimensional pudiera ser algo como:

template class vector {
public:
	int dim;
	T v[N];
	vector() : dim(N) {
		for (int ii = 0; ii < N; ++ii)
			v[ii] = (T)0;
	}

	vector(const vector &w) : dim(N) {
		memcpy(v, w.v, sizeof(T)*N);
	}
};

Como se sabrá, el compilador reemplazará cualquier valor dado a N y tipo de dato para T, y generará una versión de la clase para dichos parámetros. De esta forma los ciclos son ciclos de un número constante de iteraciones, de forma que son optimizados en tiempo de compilación.

Ahora, la magia de los templates comienza acá. Imaginemos que se desea expandir la clase para poder generar un vector N dimensional a partir de uno de N-1 dimensiones (asumiendo N>1).

vector(const vector &w) : dim(N) {
	memcpy(v, w.v, sizeof(T)*(N-1));
}

El primer pensamiento que puede venir a la cabeza es que el compilador generará un número infinito de clases a partir del valor que se dé a N, siguiente hacia abajo hasta hacer overflow de enteros, quedarse sin espacio en la pila, o hasta que nuestra paciencia se agote y cancelemos la compilación ;). En realidad, es más simple (al menos en los compiladores modernos): un template debe de estar ubicado en un fichero de cabecera (léase: .h) ya que el código fuente completo debe estar disponible para poder generar las diferentes clases para cada valor de los parámetros del template. Las funciones y métodos de un .h no son compilados salvo que sean invocados en algún punto de nuestro programa. Por ende, el constructor recursivo para vector sólo será compilado cuando se instancie un objeto de esa clase que haga uso de dicho constructor. En pocas palabras, funciona. Igualmente puede hacerse con N+1, puesto que la lógica es la misma.

Repito, esto no pretende ser un curso de templates sino algunas cosas curiosas sobre ellos. En un futuro post hablaré un poco sobre la "sobrecarga" de templates y veremos si se me presenta alguna otra "curiosidad" que valga la pena postear ;).