Bienvenidos sean a este post, hoy veremos otro tema con los templates.
Hasta ahora hemos visto algunas formas de utilizar a templates. Tanto para generar clases genericas como funciones genericas. Asi como tambien hemos mencionado que en los templates podemos pasar varios identificadores para que representen distintos tipos de datos. Pero a partir de C++11 tenemos la posibilidad de poder crear unos templates con una cantidad de identificadores variables. Veamos como son las sintaxis de ambos casos:
template <typename... Args>
class X { ... resto de la clase
template <typename... Args>
void foo( argumento) { ... resto de la funcion
Siempre usaremos a typename… seguido del identificador. Despues lo aplicaremos como vinimos viendo hasta ahora. Veamos un par de ejemplos genericos:
X<> x0; // Esta clase tiene 0 argumentos.
x<int, float, std::string> x2; // Esta clase posee tres argumentos.
foo<int, float, std::string> ( argumentos ) // funcion con esos tres datos.
Como pueden ver, esto nos permitira tener una variante a la cantidad de tipos de datos genericos que puede manejar tanto nuestras clases como nuestras funciones. Veamos el siguiente caso:
template <typename T, typename... Args>
En este caso, tanto la clase como la funcion que le asignemos este template manejara como minimo un tipo de dato, y los que agreguemos luego seran variados. Para entender este concepto vamos a analizar el siguiente ejemplo:
#include <iostream>
#include <math.h>
double minimo(double n){
return n;
}
template<typename... Numeros>
double minimo(double m, Numeros... n){
return fmin(m, minimo(n...));
}
int main() {
double x1 = minimo(2);
double x2 = minimo(2, 3);
double x3 = minimo(2, 3, 4, 5, 0.1, 4.7,5.6, 9.9);
std::cout << "x1="<<x1<<"\tx2="<<x2<<"\tx3="<<x3<<std::endl;
return 0;
}
Incluiremos a la libreria math.h para poder usar a la funcion fmin. Lo siguiente sera definir una funcion llamada minimo para que reciba un solo valor y lo devuelva, dado que siempre sera el minimo, y luego hacemos una sobrecarga sobre este. Pero le aplicaremos un template variado. A esta sobrecarga le asignaremos un argumento para recibir un valor y el resto sera del tipo del template variado. En esta funcion devolveremos el resultado de fmin, donde compara el valor recibido y el llamado a la funcion anterior con cada uno de los valores pasados mediante el template. En el main, definiremos tres variables con distintos llamados a las funciones anteriores. En el primer caso, se llamara a la primera funcion. En el segundo caso y tercer caso, llamaremos a la segunda funcion pero uno contendra un solo valor adicional y el otro una gran variedad. Por ultimo, mostraremos en consola los valores que obtuvo fmin. Compilemos y veamos como es la salida:
$ ./variad
x1=2 x2=2 x3=0.1
$
Observen como en todos los casos nos devolvio el valor minimo. Sin importar el orden o la cantidad que informemos. El template variado podra recibir todos los valores y nos permitira usarlos sin ningun inconveniente. Vamos a analizar el siguiente ejemplo:
#include <iostream>
#include <string>
void printf_tv(const char *s)
{
while(*s) {
if (*s == '%' && *(++s) != '%')
throw std::runtime_error("Formato no valido: argumento perdido");
std::cout << *s++;
}
}
template <typename T, typename... Resto>
void printf_tv(const char *s, T v, Resto... r)
{
while(*s) {
if (*s == '%' && *(++s) != '%'){
std::cout << v;
printf_tv(s, r...);
return;
}
std::cout << *s++;
}
}
int main() {
int x = 10;
float y = 3.6;
std::string s = "tinchicus.com";
const char * msj1 = "% es un gran sitio para aprender\n";
printf_tv(msj1, s);
const char * msj2 = "Los distintos valores:\ns=%\nx=%\ny=%\n";
printf_tv(msj2, s, x, y);
return 0;
}
Como pueden observar para poder trabajar correctamente con la redundancia siempre debemos tener una funcion y la sobrecarga de esta con el template variado. Esto es asi porque la primera sera para finalizar la recursion. La primera tiene un bucle donde existe un puntero del valor recibido se repetira. En este tenemos un condicional si el puntero actual es igual al caracter % y el siguiente es distinto de este, lanzaremos una excepcion para indicar que faltan argumentos. En caso de no cumplirse mosttraremos el caracter en el puntero e incrementaremos su posicion.
La siguiente es la sobrecarga y aqui aplicaremos a la template variada. En este caso, usaremos un tipo generico para manipular informacion y luego el variado para poder manipular multiples argumentos. La sobrecarga primero recibira un tipo char, el segundo sera el tipo generico que establecimos, y el tercero sera para los argumentos adicionales. Internamente es muy similar al anterior porque tenemos el mismo condicional pero ahora cuando coincida el caracter % le pasaremos el valor, tal como hace printf, y haremos una recursion pasando al tipo caracter y luego pasaremos el resto. En caso, de no cumplirse la condicion muestra el valor del puntero acttual y lo incrementa. Esto es para el resto del texto cuando no pasemos la informacion.
Por ultimo, en el main definiremos cuatro variables de distintos tipos. Siendo el ultimo de tipo char para poder ser enviado a la funcion. Luego usaremos una funcion donde pasaremos la variable de tipo char y la de tipo string. Definimos una nueva variable de tipo char, en ambos casos aplicamos un texto y en ella pondremos un caracter de % para que sea el encargado de recibir la informacion. Nuevamente, llamamos a la funcion con la nueva variable y le pasamos todas las anteriores. Compilemos y veamos como es la salida:
$ ./variad
tinchicus.com es un gran sitio para aprender
Los distintos valores:
s=tinchicus.com
x=10
y=3.6
$
Trabaja de forma similar a printf, de la cual hablamos en este post, donde para insertar un dato dentro de un texto utilizamos al caracter %, la unica diferencia radica en como pasarlo. Para printf necesitamos especificar el tipo de dato para que sea manipulado correctamente. En nuestra funcion simplemente pasamos el caracter y luego por orden lo iremos asignando. Si bien, esto puede ser mas practico tampoco es necesario reinventar la polvora porque printf tiene muchisimas mas ventajas que esta. Pero esto lo aplicamos asi para entender que es una gran mecanica para poder manipular mas argumentos en caso de ser necesario.
En resumen, hoy hemos visto template variados, que es, para que sirve, como se utiliza, donde se pueden aplicar, asi como tambien un par de ejemplos para verlo en acccion con distintas conductas. Espero les haya resultado de utilidad sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.


Donatión
It’s for site maintenance, thanks!
$1.50
