Templates de C++ – Una Introducción
Posted by gfaraj on May 1, 2007
Los templates son muy importantes en el desarrollo de software con C++. Es sin duda una de las caracteristicas mas importantes (si no es la mas importante) de este lenguaje. Nos permite escribir codigo generico que puede ser usado con varios tipos de datos. Sin templates, se tendrian que reescribir muchas funciones y clases. Tomemos el siguiente ejemplo de una funcion que retorna el maximo de dos valores.
int max(int x, int y) { return (x < y) ? y : x; } float max(float x, float y) { return (x < y) ? y : x; }
Como podemos ver, sin templates dos funciones que tienen el mismo cuerpo se tienen que reescribir para que funcione con varios tipos. Veamos la misma funcion usando templates.
template <typename T> T max(T x, T y) { return (x < y) ? y : x; }
Esta funcion funciona con cualquier tipo que se pueda comparar con el operador <. Funciona hasta con tu propia clase si ella tiene el operador < implementado. Tambien se puede tener templates para clases. Clases como std::vector y std::list son templates y nos permiten usarlas para cualquier tipo que querramos. Veamos un ejemplo de una clase template.
template <typename T> class Puntero { T* _ptr; public: explicit Puntero(T* ptr = 0) : _ptr(ptr) {} ~Puntero() { delete _ptr; } // implementamos estos operadores para que la clase actue como puntero T& operator*() { return *_ptr; } T* operator->() { return _ptr; } }; int main() { Puntero<int> puntero_int(new int); *puntero_int = 10; Puntero<bool> puntero_bool(new bool); *puntero_bool = true; }
Ahi podemos ver una clase (incompleta) que trata de personificar un puntero. Cuando se destruye una instancia de esta clase, tambien destruye el puntero que contenia. Ahi pueden ver lo facil que es hacer una clase generica y los beneficios que esto trae. Sin templates, hubiera tenido que copiar la misma clase dos veces, cambiando ‘int’ por ‘bool’ solamente. Ahi se va notando que el reuso del codigo puede ser significativo al usar templates. Imaginense reimplementar std::vector por cada tipo que se quiera usar…
Bueno, esta solo era una pequeña introduccion. Espero que les haya gustado y volvere con algo mas avanzado la proxima.
programador said
wow que bien por fin tengo un poco de idea sobre templates
es que esta es la primera informacion que leo en espanol, todo el tiempo lo veia en ingles, y no sabia como seria la traduccion a espanol, pero veo que no se lo traduce xD
gracias por el articulo
gfaraj said
Me alegra que te haya gustado
La traduccion de la palabra “template” a español seria “plantilla”, pero prefiero mantener la palabra “template” porque asi se muestra en el codigo.
Alexi said
Hola,
Quisiera hacer una consulta..
¿Como puedes usar los template para paginas web? o como uso C++ para los sitios web
Gracias
gfaraj said
Estos templates no tienen nada que ver con los templates de una pagina web (como por ejemplo Smarty para PHP). C++ se puede usar por medio de CGI en un servidor web. Tambien se puede usar para crear controles ActiveX para Internet Explorer. Espero haber respondido tu pregunta.
Dulcinea said
Genial!!!!…creo que es la explicación mas clara y sencilla que puede haber sobre los templates… buena anotación la de que vale para clases si tienes implementado el operador
.
Enhorabuena!!!…
gfaraj said
Gracias Dulcinea. Me alegra que te halla gustado
Parmaia said
Buenas, estoy trabajando con templates y al definir mi clase en un .h y la implementacion en un .cpp tengo un error al momento del enlace como si el compilador no consiguiera la implementacion que esta en el .cpp, si lo hago todo en el mismo .h funciona perfecto, cual puede ser la causa?
Ejemplo:
MiClase.h
#ifndef MiClase_H
#define MiClase_H
template
class MiClase{
public:
MiClase();
void Algo(Tipo A);
};
#endif
MiClase.cpp
#include "MiClase.h"
template
MiClase::MiClase(){
//Nada...
}
template
void MiClase::Algo(Tipo A){
//Nada...
}
main.cpp
#include "MiClase.h"
int main(){
MiClase C;
C.Algo(5);
return 0;
}
Para compilar:
g++ MiClase.cpp main.cpp -o Ejecutable
Error:
/tmp/cc6XNSRb.o: In function `main’:
main.cpp:(.text+0×194): undefined reference to `MiClase::MiClase()’
main.cpp:(.text+0×1a7): undefined reference to `MiClase::Algo(int)’
collect2: ld devolvió el estado de salida 1
Gracias de antemano por cualquier comentario al respecto.
Parmaia said
Perdon, no salieron los < > escribo el ejemplo de nuevo:
MiClase.h
#ifndef MiClase_H
#define MiClase_H
template <class Tipo>
class MiClase{
public:
MiClase();
void Algo(Tipo A);
};
#endif
MiClase.cpp
#include "MiClase.h"
template <class Tipo>
MiClase<Tipo>::MiClase(){
//Nada...
}
template <class Tipo>
void MiClase<Tipo>::Algo(Tipo A){
//Nada...
}
main.cpp
#include "MiClase.h"
int main(){
MiClase<int> C;
C.Algo(5);
return 0;
}
Para compilar:
g++ MiClase.cpp main.cpp -o Ejecutable
Error:
/tmp/cc6XNSRb.o: In function `main’:
main.cpp:(.text+0×194): undefined reference to `MiClase<int>::MiClase()’
main.cpp:(.text+0×1a7): undefined reference to `MiClase<int>::Algo(int)’
collect2: ld devolvió el estado de salida 1
Gracias de antemano por cualquier comentario al respecto.
gfaraj said
@Parmaia:
Las definiciones de los templates requieren estar disponibles al momento de compilarse. Por esta razon, lo ideal es poner todo en el header (.h). Existe lo que se llama “explicit instantiation,” que permite instanciar un template para un grupo de tipos en especifico (por ejemplo, MiClase<int> y MiClase<float>). Esto permite poner las definiciones en un .cpp, pero otros archivos solo podran usar el template con los tipos especificos con los que fue instanciado explicitamente.
template class MiClase<int>;
template class MiClase<float>;
Otra opcion, es el keyword “export.” El problema aqui es que muy pocos compiladores han implementado esto y la verdad que al final no es muy util. Lo mas practico es definir todo en el .h.
JHAx86 said
Gracias, en la Wiki de OGRE te mandan a comprar un libro si no sabes lo que son templates. Pero gracias a ti no tengo que perder más tiempo, cosas como éstas enriquecen la web.
Saludos.
yo said
Tengo algunas dudas existenciales, no sé si este es el mejor sitio
Un asterisco delante de una variable es un puntero, hasta aqui ok:
*puntero_int
pero detras de un tipo o una variable que es?
T* operator
Un ampersand delante de una variable, es un paso por referencia:
&var_name
pero detras de un tipo que es?
T& operator*
Muchas gracias
leon said
Eh creo que ya no vas a volver a leer esto, pero por si alguien mas pasa y tiene dudas parecidas no da para dejarlas asi sin contestar =)
*puntero_int
no es un puntero, el puntero es “puntero_int” (una variable de tipo puntero). El * delante de una variable se pude leer como “valor apuntado por”. Te queda “valor apuntado por puntero_int”.
T* puntero
Eso define un puntero a algo de tipo T. El * despues de un nombre de tipo es como decir “puntero a”. T* se lee como “puntero a T” y es un tipo de variable.
&var_name
El & delante de un nombre de variable NO es una referencia, es la direccion de memoria del contenido de var_name. Por decirlo sin mucha “correctancia”, te devuelve un puntero a la variable. Se podria leer como “puntero a”. Te queda “puntero a var_name” (lo mas correcto es leerlo como “direccion de”). Creo que & usado asi se llama “operador de indireccion”, pero no me juego a ello.
T&
El & despues de un tipo de variable quiere decir, ahora si, que es una referencia. En este caso quiere decir que el operador te devuelve una referencia a algo de tipo T (el contenido del puntero):
T& operator*() { return *_ptr; }
Julio said
Es la mejor explicacion de templates que vi en mi vida, y eso que lei un monton por que cuando las vi por primera vez no las podia entender ni un poquitin!
gfaraj sos un maestro! gracias!
Clelia said
Que buena informacion has publicado en este blog!!! Esta explicado de forma sumamente sencilla.
Muchas gracias, continua asi.
carlos said
excelente…. gracias por las explicaciones… todas son muy utiles!