Archivo por meses: enero 2020

Curso de plantillas en C++: uso en funciones

Antes de continuar con las funciones quedó pendiente la sintaxis de las plantillas:

template < LISTA_DE_LA_PANTILLA > SOBRE_LO_QUE_APLICA_LA_PANTILLA

Bueno, creo que está claro: se usa la palabra reservada template y entre brakets (los simbolitos ‘<‘ y ‘>‘) se pone la lista de cosas que queremos que se puedan hacer plantilla. Finalmente va la parte sobre la que vamos a aplicar la plantilla, que puede ser una estructura o unión, una clase, una función, un renombrado de tipo con using (a partir del estándar de 2011) o una declaración de variable (a partir del estándar de 2014).

Y con esto se termina esta breve explicación. El resto lo iremos viendo con ejemplos.

Ahora sí: Funciones

En el momento en el que podemos tener tipos como plantillas surge el problema de poder usarlos en funciones. En este punto la lógica es sencilla, si tengo que pasar a una función un tipo que es una plantilla, la función también debe ser una plantilla.

template<class T> struct mi_tipo {
   /* Da igual lo que vaya aquí para el ejemplo */
};

template<class T>
void una_funcion(mi_tipo<T> valor) {
   /* Esta funcion aceptará cualquier mi_tipo */
}

De este modo, desde una_funcion tendríamos acceso a todas las funciones miembro y variables miembro de mi_tipo. A partir de aquí lo usaríamos de forma normal como cualquier otra variable.

Hay otra forma de crear la plantilla para que acepte cualquier cosa:

template<class T>
void otra_funcion(T valor) {
   /* Esta funcion aceptara cualquier tipo, incluido mi_tipo */
}

Con este código, otra_funcion acepta cualquier tipo de dato. Si intentamos acceder a alguna variable miembro o función miembro de valor el compilador dará error si no está implementada en el tipo T.

Un ejemplo práctico

Hasta ahora hemos visto un poco por encima cómo hacer plantillas sencillas, pero toca ver algo que tenga alguna utilidad. Por eso vamos hacer una clase que implemente un array que pueda devolver su tamaño con una función (como en java).

Actualmente ya existe una clase que hace eso en el estándar. Es std::array.

/* Este codigo es compatible C++03 */
#include <iostream>
#include <stdexcept>

template<class Tipo, int Tam> class array {
   public:
      Tipo& operator[](int p) {
         if (p >= Tam) throw std::out_of_range(std::string("Te saliste del rango"));
         return valores_[p];
      }
      int tam() const {
         return Tam;
      }
   private:
      Tipo valores_[Tam];
};

int main() {
   array<int, 5> valores;
   for (int i = 0; i < valores.tam(); i++)
      valores[i] = i*2;

   for (int i = 0; i < valores.tam(); i++)
      std::cout << valores[i] << std::endl;

   return 0;
}

En las siguientes entregas profundizaremos más en lo que se puede hacer con las plantillas.