Plantillas en C++

Recuerdo cuando empecé a aprender C++ que la cosa que menos entendía era el uso de plantillas. Debo reconocer que me ha costado mucho comprender como funciona porque era algo completamente diferente a lo que hasta entonces había visto.

Por otro lado, hemos visto en los últimos tiempos como gran cantidad de arquitecturas han copiado el modelo para implementarlo a su modo. Aquí es donde vemos los genéricos de Java y de .Net. El problema es que no tienen ni de cerca la misma potencia que el sistema de C++, pero que como ventaja consumen menos espacio de ejecutable.

Para entrar un poco en materia, comentar que las plantillas de C++ son como documentos en los que dejamos lineas en blanco y luego las rellenamos cuando ya sabemos qué queremos poner en ahí. Pero en C++ no ha líneas en blanco, estas tienen nombre.

La principal ventaja de este sistema es que permite programar clases genéricas, como pueda ser una clase lista que automáticamente se adapte al tipo que debe contener. La segunda ventaja es el rendimiento, por el mismo motivo anterior.

Para empezar a ver un poco como va la cosa vamos a ver un ejemplo sencillo de plantilla:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
template<typename T, int S>
class array
{
private:
   T *ptr;
 
public:
   array()
   {
      ptr = new T[S];
   }
 
   T& operator[](int idx)
   {
      return T[idx];
   }
 
   int size()
   {
      return S;
   }
};
//</typename>

Como vemos, hemos utilizado la palabra reservada template para indicar que se trata de una plantilla y luego, entre los símbolos < y > hemos introducido la lista de elementos de la plantilla. Estos elementos son los tipos y nombres de los valores a sustituir. En este caso son T de tipo typename y S de tipo int. Esto significa que cada vez que dentro de la clase aparezca T deberá sustituirse por su corresponditente valor pasado en la plantilla y que necesariamente deberá ser un tipo de dato (por ejemplo un int, una clase, etc.) y que cada vez que aparezca S deberá sustituirse por su valor que deberá ser un número entero. Para utilizar la plantilla sólo deberemos hacer lo siguiente:

1
2
3
4
5
6
7
8
9
10
int main(void)
{
   using namespace std;
 
   array<int , 5> a;
   cout < < "Tamaño del array: " << a.size() << endl;
   a[1] = 5;
 
   return 0;
}

Como vemos, lo único que hemos hecho ha sido añadir al nombre del la clase la lista de argumentos. En este caso concreto, deberá devolver que el tamaño es 5, que es el indicado en el parámetro de la plantilla.

Si nos fijamos en bibliotecas como STL o Boost, hacen un uso intensivo de las plantillas. El principal motivo es que C++ está optimizado para funcionar con plantillas, así que se prefieren al uso de mecanismos como la herencia. Además, la herencia hace que las llamadas a métodos sean más lentos, por lo que también se evita. Es en este momento cuando nos podemos preguntar el cómo hace C++ entonces para garantizar que se implementan ciertas funcionalidades. Por ejemplo, si queremos tener una lista ordenada, nos interesa que los elementos de la lista puedan compararse entre ellos con el operador <=. Pues la respuesta es sencilla: en la clase de plantilla simplemente utilizamos ese método y en tiempo de compilación se comprueba si está o no. Por ejemplo:

1
2
3
4
5
6
template<typename T>
T& mayor(T& a, T& b)
{
   return a >= b ? a : b;
}
//</typename>

Hemos creado una función mayor que devuelve el mayor de dos elementos de tipo T. Los elementos de tipo T deben sobrecargar el operador >= para que funcione. Como se ve, no es necesario hacer herencia de ningún tipo, el compilador detecta automáticamente si está o no sobrecargado y dará el correspondiente error en caso necesario (si miramos el caso de Java o de .Net veremos como sí es necesario hacer herencia para que el mecanismo de genéricos funcione de este modo).

Debo decir que el tema de las plantillas está muy bien y se puede hacer muchas cosas interesantes, como la clase array, que funciona igual que un array y que tiene un rendimiento muy parecido (benditos métodos inline de C++).

Otro día, seguiré hablando sobre plantillas, que dan para mucho.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *