2012-02-07 13 views
9

En Andrei's talk on GoingNative 2012 habla de plantillas variables, y explica en un punto a modo de ejemplo cómo funcionan las expansiones del paquete de parámetros. Siendo bastante nuevo en este tema, me resultó bastante difícil seguir el funcionamiento de cada caso, ¿podría explicarme cómo funciona la expansión en cada llamada de función de gun?Variaded Templates pack expansions

template<class... Ts> void fun(Ts... vs) { 
    gun(A<Ts...>::hun(vs)...); 
    gun(A<Ts...>::hun(vs...)); 
    gun(A<Ts>::hun(vs)...); 
} 
+1

es probable que desee especificar que 'Ts' es (por ejemplo)' void *, int, char, std :: string' o algo así, por lo que las respuestas alinear un poco mejor. –

Respuesta

9

1.

gun(A<Ts...>::hun(vs)...) 
=> gun(A<T1, T2, …, Tn>::hun(vs)...) 
=> gun(A<T1, T2, …, Tn>::hun(v1), 
     A<T1, T2, …, Tn>::hun(v2), 
     …, 
     A<T1, T2, …, Tn>::hun(vm)) 

2.

gun(A<Ts...>::hun(vs...)) 
=> gun(A<T1, T2, …, Tn>::hun(vs...)) 
=> gun(A<T1, T2, …, Tn>::hun(v1, v2, …, vm)) 

Esto debería ser obvio.

3.

gun(A<Ts>::hun(vs)...) 
=> gun(A<T1>::hun(v1), A<T2>::hun(v2), …, A<Tn>::hun(vn)) 

(En este caso el programa no se compilará si las longitudes de Ts y VS difieren)


El ... habrá expandido un patrón (que incluye paquetes de parámetros) precediéndola, lo que significa que. En foo(Ts, Us, Vs)..., cada miembro de la lista Ts, Us, Vs (enumerados en el paso de bloqueo) será subsituted en ese patrón, y se forma una lista coma:

foo(Ts, Us, Vs)... 
=> foo(T1, U1, V1), foo(T2, U2, V2), …, foo(Tn, Un, Vn) 

y si hay expansiones anidada, los patrones más íntimos se expandirá primero. Por lo tanto, en el caso 1, el patrón Ts se expandirá primero en T1, T2, …, Tn. Y luego, el patrón que precede al externo ... es A<T1, T2, …, Tn>::fun(vs) - tenga en cuenta que Ts se ha expandido, por lo que se expandirá a A<T1, T2, …, Tn>::fun(v1), <T1, T2, …, Tn>::fun(v2), …, <T1, T2, …, Tn>::fun(vm) sustituyendo v1, v2, etc. en vs.

+0

Las longitudes de 'Ts' y' vs' _can't_ difieren. Es como decir que no compilará si '5' es más de un' int'. –

+0

@MooingDuck: Las longitudes son las mismas solo porque la función se declara como 'plantilla void fun (Ts ... vs)'. ¿Qué pasa si uno declara otra 'plantilla void iun (Us ... vs)': p – kennytm

+0

@KennyTM: el paquete de parámetros de la plantilla debe ser el último argumento de la plantilla; de lo contrario, no puede deducirse o especificado (14.1.11). –

4

La respuesta de KennyTM es perfecta. También me gustan las muestras. Pero dado que su respuesta es abstracta, no tenía ganas de agregar demos a su respuesta es lo correcto. Entonces demos para su respuesta están aquí. Supongo que su respuesta es correcta, yo tampoco sé nada. (Si usted votó positivamente esto, también votó por él)

Obviamente, esto es todo el psudocódigo que solo muestra los estados expandidos.

void foo<void*,int,char,std::string>(nullptr, 32, '7', "BANANA") { 
    //gun(A<Ts...>::hun(vs)...); 
    gun(A<void*,int,char,std::string>::hun(nullptr) 
     ,A<void*,int,char,std::string>::hun(32) 
     ,A<void*,int,char,std::string>::hun('7') 
     ,A<void*,int,char,std::string>::hun("BANANA") 
     ); 
    //gun(A<Ts...>::hun(vs...)); 
    gun(A<void*,int,char,std::string>::hun(nullptr, 32, '7', "BANANA"); 
    //gun(A<Ts>::hun(vs)...); 
    gun(A<void*>::hun(nullptr) 
     ,A<int>::hun(32), 
     ,A<char>::hun('7'), 
     ,A<std::string>::hun("BANANA") 
     ); 
} 
+1

oh hey! ¡Acabo de encontrar la diapositiva de la que salió esta pregunta! –

+2

¿Usando 'NULL' con plantillas variadic? Eso es como usar un Ferrari para sacar un remolque;) –