2012-10-10 31 views
5

Lo siento por la pregunta complicada, pero básicamente la idea es muy simple. Tengo una plantilla de clase variadic:¿Es posible definir una plantilla de clase variadica de C++ 11 cuya cardinalidad de parámetros variados dependa de un parámetro de plantilla entera?

template<class P1, class P2, class ... P3s> 
class A 
{ 
    ... 
}; 

me gustaría tener un generador de A-clases que toma un parámetro de plantilla entero N y crea la instancia de una clase A con los parámetros N P3S. Al igual que:

template<class P1, class P2, class P3, int N> 
class GenA : /* somehow */ : public A<P1, P2, /* N times */ P3, P3, ...> 
{ 
    ... 
}; 

Así que el uso sería:

// Generates A<Class1, Class2, Class3, Class3, Class3> 
GenA<Class1, Class2, Class3, 3> a; 

ya he intentado hacer eso con la recursividad tiempo de compilación y la especialización parcial

template <class P1, class P2, int N, class P3> 
class GenA : public GenA<P1, P2, N-1, P3, P3> 
{ 
    ... 
} 

template <class P1, class P2, int N, class ... P3s> 
class GenA<P1, P2, 0, P3s ...> : public A<P1, P2, P3s, ...> 
{ 
    ... 
} 

obstante C++ 11 no reconoce la segunda plantilla es una especialización de la primera (porque es, de hecho, diferente) y nunca llega al caso base de la recursión (deja de quejarse sobre demasiados niveles de recursión). ¿Algunas ideas?

Gracias
Tunnuz

+0

Parece difícil de hacer sin excesivas especializaciones de plantillas. –

+0

Después de haber elegido una de las respuestas, ¿podría proporcionar un punto de referencia de las soluciones? – pmr

Respuesta

5
template<class P1, class P2, class... P3s> 
class A {}; 

template<class... Ps> 
struct TypeList {}; 

template<class P1, class P2, class P3, unsigned N, class P> struct GenHelp; 

template<class P1, class P2, class P3, class... Ps> 
struct GenHelp<P1, P2, P3, 0, TypeList<Ps...> > 
{ 
    typedef A<P1, P2, Ps... > AType; 
}; 

template<class P1, class P2, class P3, unsigned N, class... Ps> 
struct GenHelp<P1, P2, P3, N, TypeList<Ps...> > : public GenHelp<P1, P2, P3, N-1, TypeList<P3, Ps...> > 
{}; 

template<class P1, class P2, class P3, unsigned N> 
class GenA : public GenHelp<P1, P2, P3, N, TypeList<> >::AType 
{}; 
+0

¡Brillante! Tomaré esto porque es similar a lo que estaba tratando de hacer. – tunnuz

5

Puede utilizar los parámetros de plantilla plantilla variadic para hacer esto. En esta implementación , simplemente comenzamos con un paquete de argumentos que consiste en P1 y P3 y seguimos extendiéndolo. Al final instanciamos el parámetro de plantilla de plantilla variadic con ese paquete de argumentos.

template<class P1, class P2, class ... P3s> 
struct A {}; 

template<template<class... Args> class AT, typename P3, int N, 
     typename... Already> 
struct GenAImpl { 
    typedef typename GenAImpl<AT, P3, N - 1, Already..., P3>::type type; 
}; 

template<template<class... Args> class AT, typename P3, 
     typename... Already> 
struct GenAImpl<AT, P3, 0, Already...> { 
    typedef AT<Already...> type; 
}; 


template<class P1, class P2, class P3, int N> 
struct GenA : GenAImpl<A, P3, N, P1, P2> 
{}; 

int main() 
{ 
    GenA<int, double, float, 3>::type X; 
    return 0; 
} 

Tenga en cuenta que añadiendo a las listas es a menudo una mala idea (al menos en idiomas verdadera funcionales, no tengo ni idea de si eso en realidad impactos C++ rendimiento del compilador) y que está mejor con Consing juntos y revirtiéndolo al final.

+0

Pero también votaré esta solución. – tunnuz

Cuestiones relacionadas