2011-01-16 18 views
15

Continuando con my journey into the world of variadic templates, me encontré con otro problema.especialización de plantilla parcial con varios paquetes de parámetros de plantilla

Suponiendo que la siguiente clase de plantilla:

template < typename T > 
struct foo 
{ 
    //default implementation 
}; 

es posible especializarse en parte por instancias plantilla variadic como este:

template < template < typename ... > class T, typename ...Args > 
struct foo< T<Args...> > 
{ 
    //specialized implementation 
}; 

Con esto, foo<int> corresponderá a la implementación predeterminada y foo< std::tuple< int, char > > a la implementación especializada.

Sin embargo, las cosas se vuelven más complicadas cuando se usan varios parámetros de plantilla. Por ejemplo, si tenemos la siguiente clase de plantilla

template < typename T, typename U > 
struct bar {}; 

y queremos especializar parcialmente, tal como lo hicimos para foo, no podemos hacer

template < template < typename ... > class T, typename ...TArgs, 
      template < typename ... > class U, typename ...UArgs > 
struct bar< T<TArgs...>, U<UArgs...> > {}; 

//This would correspond to the specialized version with 
//T=std::tuple, 
//TArgs=int,char 
//U=std::tuple, 
//UArgs=float 
bar< std::tuple< int, char >, std::tuple<float> > b; 

De hecho, si estoy en lo correcto, sólo nos queda tiene un paquete de parámetros de plantilla y debe colocarse al final de la lista de parámetros. Entiendo por qué esto es obligatorio en las declaraciones de plantillas, pero para cierta especialización parcial de plantillas (como en el ejemplo anterior), esto no debería ser un problema.

¿Es posible lograr la especialización de plantilla parcial con múltiples paquetes de parámetros de plantilla?


Editar: Ahora me siento tonta ... el código que di arriba compila perfectamente (al menos con gcc 4.5). El error de compilación que tuve no se debió a múltiples paquetes de parámetros, sino a su uso como parámetros de funciones miembro. En la especialización parcial de bar, traté de definir una función miembro que tiene en cuenta tanto TArgs y UArgs parámetros:

template < template < typename ... > class T, typename ...TArgs, 
      template < typename ... > class U, typename ...UArgs > 
struct bar< T<TArgs...>, U<UArgs...> > 
{ 
    void method(TArgs... targs, UArgs... uargs) //compile error here 
    { 
    } 
}; 

En la declaración de la función miembro, gcc me da el error

parámetros paquetes deben estar al final de la lista de parámetros.

Por lo que puedo decir, el compilador debería ser capaz de definir la función de miembro correcta para una instancia de plantilla determinada, p. bar< std::tuple< int, char >, std::tuple<float> > debe contener una función de miembro void method(int, char, float). ¿Estoy haciendo algo mal? ¿O estoy tratando de hacer algo que no es posible? Si es así, ¿hay una buena razón por la cual esto no es posible?

+0

Limpio, no sabía que pudiera especializar/especificar (parte de) los elementos de una lista de plantillas como las propias plantillas. – JAB

Respuesta

6

Probablemente esta respuesta no aclare su pregunta directamente, pero el siguiente código compilado en ideone (gcc-4.5.1) cuando la probé.

#include <cstdio> 
#include <tuple> 

template< class, class > struct S { 
    S() { puts("primary"); } 
}; 

template< 
    template<class...> class T, class...TArgs 
, template<class...> class U, class...UArgs 
> 
struct S< T<TArgs...>, U<UArgs...> > { 
    S() { puts("specialized"); } 
}; 

int main() 
{ 
    S< int, int > p;          // "primary" 
    S< std::tuple< int, char >, std::tuple<float> > s; // "specialised" 
} 

No estoy seguro de que este código es estrictamente conformes, pero por lo que leí N3225 14.5.3, no pude encontrar la declaración que menciona ese paquete parámetro de plantilla tiene que ser la última plantilla parámetro.

Editar:
releo N3225 y ha encontrado los siguientes estados:

8.3.5/4 Si el parámetro-declaración-cláusula termina con una elipsis o un paquete de parámetro función (14.5.3), el número de argumentos será igual a o mayor que el número de parámetros que no tienen un argumento predeterminado y no son paquetes de parámetros de función .

14.8.2.5/10 [Nota: Un paquete de parámetros de función solo puede ocurrir en el al final de un parameter-declarationlist (8.3.5). -fin nota]

Así que, como usted ha mencionado, el paquete de parámetro de función tiene que ser el último parámetro por desgracia.
Una función miembro no plantilla de una plantilla de clase es una función ordinaria para esa clase cuando se crea una instancia (totalmente especializada). Así que deseo que el código en esta pregunta se pueda compilar lógicamente, como un caso especial .

+0

¡Tiene razón, el código compila perfectamente! El problema que agregué fue de hecho un poco diferente, voy a editar la pregunta ... Perdón por la inconveniencia ... –

+0

@LucTouraille: No te preocupes :-) Esta fue una buena ocasión de autoeducación para mí. –

+0

Algo me hace pensar que la cita no se debe aplicar aquí porque ambos paquetes de parámetros ya son conocidos y solo necesitan expandirse. no me sorprendería si clang aceptara este código. –

Cuestiones relacionadas