Pregunta

mi viaje en el mundo de las plantillas variadic , me encontré con otro problema.

Si se asume la siguiente clase de plantilla:

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

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

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

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

Sin embargo, las cosas se vuelven más complicadas cuando se utilizan 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 cierto, que sólo puede tener un parámetro de paquete de plantilla y que debe colocarse al final de la lista de parámetros. Entiendo por qué esto es obligatorio en las declaraciones de la plantilla, pero para cierta especialización de plantilla parcial (como el ejemplo anterior), esto no debería ser un problema.

¿Es posible lograr la especialización de plantilla parcial con varios paquetes de parámetro 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 tenía no era debido a múltiples paquetes de parámetros, pero debido a su uso como parámetros de funciones miembro. En la especialización parcial de bar, traté de definir una función miembro que lleva ambos parámetros TArgs y UArgs:

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 en el final de la lista de parámetros.

Por lo que yo puedo decir, el compilador debe ser capaz de definir la función de miembro correcto para una instanciación plantilla dada, por ejemplo, bar< std::tuple< int, char >, std::tuple< float > > debe contener una void method( int, char, float ) función miembro. ¿Estoy haciendo algo mal? O estoy tratando de hacer algo que no es posible? Si es así, ¿hay una razón buena por qué no es posible?

¿Fue útil?

Solución

Es probable que esta respuesta no se borrará a su pregunta directamente, pero el siguiente código compilado en Ideone (gcc-4.5.1) cuando 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 he leído N3225 14.5.3, no pude encontrar la declaración que menciona ese paquete parámetro de plantilla tiene que ser el último parámetro de plantilla.

Editar:
Releo N3225 y encontramos las siguientes declaraciones:

8.3.5 / 4 Si la declaración-cláusula parámetro termina con una elipsis o una paquete de parámetro de 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 defecto argumento y no son funciones paquetes de parámetros.

14.8.2.5/10 [Nota: Un paquete de parámetro de función sólo puede ocurrir en el final de una parámetro-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 especializado). Así que me gustaría que el código en esta pregunta puede ser compilado lógicamente, como una caso especial.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top