2009-11-25 16 views
9

quiero especializar una plantilla de clase con la siguiente función:especialización de plantilla con un tipo a plantillas

template <typename T> 
class Foo 
{ 
public: 
    static int bar(); 
}; 

La función no tiene argumentos y debe devolver un resultado basado en el tipo de Foo. (En este ejemplo de juguete, volvemos el número de bytes del tipo, pero en la aplicación real que queremos volver algún objeto meta-datos.) La especialización funciona para tipos totalmente especificadas:

// specialization 1: works 
template <> 
int Foo<int>::bar() { return 4; } 

// specialization 2: works 
template <> 
int Foo<double>::bar() { return 8; } 

// specialization 3: works 
typedef pair<int, int> IntPair; 
template <> 
int Foo<IntPair>::bar() { return 2 * Foo<int>::bar(); } 

Sin embargo, Me gustaría generalizar esto a tipos que dependen de (otros) parámetros de plantilla en sí mismos. Adición de las siguientes especialidades da un error en tiempo de compilación (VS2005):

// specialization 4: ERROR! 
template <> 
template <typename U, typename V> 
int Foo<std::pair<U, V> >::bar() { return Foo<U>::bar() + Foo<V>::bar(); } 

Estoy asumiendo que esto no es legal C++, pero ¿por qué? ¿Y hay una manera de implementar este tipo de patrón elegantemente?

+1

Tenga en cuenta, sin embargo, que no es necesario ningún especializaciones para devolver el tamaño de T : 'static int Foo() {return sizeof (T); } ' Me pregunto si ese tipo de patrón podría no ayudar con su problema real. – UncleBens

Respuesta

7

especialización Partitial es válida sólo para las clases, no funciones.

Solución:

template <typename U, typename V> 
class Foo<std::pair<U, V> > { 
public: 
static int bar() { return Foo<U>::bar() + Foo<V>::bar(); } 
}; 

Si no desea especializarse clase completo, utilice estructura auxiliar

template<class T> 
struct aux { 
    static int bar(); 
}; 

template <>int aux <int>::bar() { return 4; } 
template <>int aux <double>::bar() { return 8; } 

template <typename U, typename V> 
struct aux <std::pair<U, V> > { 
    static int bar() { return Foo<U>::bar() + Foo<V>::bar(); } 
}; 

template<class T> 
class Foo : aux<T> { 
    // ... 
}; 
+1

En el ejemplo, todas las especializaciones son especializaciones de clase – TimW

+1

Sí. derecho. La función partitial specialize está prohibida. Es posible crear una clase base solo para la barra de funciones. –

+0

@TimW, en la pregunta, el truco es que la clase no está especializada.Esto está fuera del estándar: "Una función miembro, una clase miembro o un miembro de datos estáticos de una plantilla de clase pueden estar explícitamente especializados para una especialización de clase que está instanciada implícitamente; si dicha especialización explícita para el miembro de una clase se llama una plantilla una función de miembro especial implícitamente declarada (cláusula 12), el programa está mal formado. ". Es una especialización para una instanciación implícita determinada (por lo tanto, no hay dependencia de parámetros de plantilla) de esa plantilla (no para ninguna especialización parcial). –

5

Es perfectamente legal en C++, es Especialización parcial de plantillas.
Retire la template <> y si no lo hace ya existe agregar la especialización explícita plantilla de clase y debe compilar en VS2005 (pero no en VC6)

// explicit class template specialization 
template <typename U, typename V> 
class Foo<std::pair<U, V> > 
{ 
public: 
    static int bar(); 
}; 

template <typename U, typename V> 
int Foo<std::pair<U, V> >::bar() { return Foo<U>::bar() + Foo<V>::bar(); } 
+1

@litb En lo que puedo ver, todas sus funciones son especializaciones de clase. No veo ninguna plantilla de función, ¿verdad? – TimW

+0

@TimW: cuando declara una plantilla de clase, cada función miembro es una plantilla de función independiente. El OP intenta especializar una plantilla de función miembro sin especializar toda la plantilla de clase. Ese es el punto. Sin embargo, la especialización parcial no es compatible con las plantillas de funciones. Ese es el problema. – AnT

+0

@TimW, no hay una plantilla de función. Pero tampoco existe una especialización de plantilla de clase explícita. Vea arriba para la cotización estándar: este es un caso especial en el Estándar, y permite explícitamente especializar miembros de plantillas de clases que no sean de plantilla, sin especializar explícitamente su plantilla de clase completa. Funciona nombrando una instanciación implícita determinada (en su ejemplo, por ejemplo 'Foo ' o 'Foo ') que en ausencia de especializaciones parciales de 'Foo' seleccionará la plantilla primaria y especializará el miembro' bar' de la misma. –

Cuestiones relacionadas