2012-05-03 18 views
11

Recientemente comencé a usar C++ 11, y lo he leído en un tutorial sobre plantillas variadic. Tengo entendido que podemos definir una plantilla como esta variadicManejo de plantillas variadic en C++ 11

// example class that uses variadic template 
template<typename ...Args> struct mtuple; 

pero ¿cómo puedo manejar los argumentos de plantilla de la clase mtuple (es decir, ¿cómo sería la get<int>(mtuple_obj) parece?)?

+4

La magia de plantillas variables es realmente mágica, tiene que experimentar con ella, así como mirar muchas muestras de códigos diferentes para ver qué y por qué está sucediendo allí. [Aquí está mi intento de escribir mi propia clase Tuple (aunque no mire 'Tie()'; D)] (https://github.com/griwes/LibRose/blob/master/librosec%2B%2B/tuple .hxx), como uno de esos ejemplos de código, también hay muchos aquí, en SO - navegue a través de [tag: variadic-templates] e intente comprenderlos. – Griwes

+1

par de interesantes preguntas relacionadas: http://stackoverflow.com/a/7868427/170521 y http://stackoverflow.com/q/7870498/170521 – lurscher

Respuesta

4

El aspecto de get<1>(t) dependerá de la implementación de mtuple. Una implementación típica hereda recíprocamente de un tipo que contiene cada argumento, por lo que mtuple<A,B,C> hereda de TupleHead<A> (que tiene un miembro de tipo A) y también hereda de TupleTail<B,C>. TupleTail<B,C> hereda de TupleHead<B> (que tiene un miembro del tipo B) y TupleTail<C>. TupleTail<C> hereda de TupleHead<C>

Ahora, si se le da cada clase base un parámetro entero demasiado (que tiene un miembro de tipo C.):

mtuple<A,B,C> hereda de TupleHead<0,A> y TupleTail<1,B,C>

TupleTail<1,B,C> hereda de TupleHead<1,B> y TupleTail<2,C>

TupleTail<2,C> hereda de TupleHead<2,C>

Ahora es relativamente simple escribir get<1>, porque mtuple tiene una única clase base única de tipo TupleHead<1,B> que se puede obtener mediante una conversión ascendente, y luego devuelve el miembro B de esa clase base.

[Editar: get<1>(m) necesita saber el tipo B que corresponde al elemento de la tupla con el índice 1, para que utilice algo como std::tuple_element que también se basa en la jerarquía de herencia recursivo descrito anteriormente y utiliza la especialización parcial para obtener la base TupleHead<1,T> clase con índice 1, luego determina el parámetro T en esa especialización parcial, que da B en mi ejemplo.]

Muchas de las técnicas utilizadas con plantillas variadic son técnicas de programación funcional, como operar en el primer elemento de la plantilla paquete de parámetros, luego recursivamente haciendo lo mismo en el resto del paquete, hasta que haya Ocessed todos los elementos.No hay muchas cosas que pueda hacer con un paquete de parámetros de plantilla directamente, excepto contar su tamaño (con sizeof...) o instanciar otra plantilla con él, por lo que el enfoque habitual es crear otra plantilla que separa el paquete Args en ArgHead, ArgsTail... y procesa el encabezado , luego recursivamente haga lo mismo a ArgsTail

4

No hay un mecanismo simple para iterar sobre los valores de una plantilla variadic. Pero esto puede hacerse recursivamente. He aquí un ejemplo:

template<typename T, typename... Args> 
void print_values(const char *s, T value, Args... args) 
{ 
    while (*s) { 
     if (*s == '%' && *(++s) != '%') { 
      std::cout << value; 
      ++s; 
      print_values(s, args...); 
      return; 
     } 
     cout << *(s++); 
    } 
} 

Por lo tanto, si llamo print_values("%d %d %d", 1, 2, 3) consigo este árbol de recursión:

print_values("%d %d %d", 1, 2, 3) // value -> 1, args... -> 2,3 
print_values("%d %d", 2, 3) // value -> 2, args... -> 3 
print_values("%d", 3) // value -> 3, args... -> NULL 
print_values("") // value -> NULL, args... -> NULL 

recursiva que llamo print_values() incluso cuando s * == 0 para detectar argumentos adicionales

Fuente: http://en.wikipedia.org/wiki/Variadic_templates

Cuestiones relacionadas