2012-04-23 28 views
16

Dado:especialización parcial de un método en una clase de plantilla

struct A 
{ 
    virtual bool what() = 0; 
}; 

template<typename T, typename Q> 
struct B : public A 
{ 
    virtual bool what(); 
}; 

quiero especializar parcialmente what como:

template<typename T, typename Q> 
bool B<T, Q>::what() 
{ 
    return true; 
} 

template<typename Q> 
bool B<float, Q>::what() 
{ 
    return false; 
} 

pero parece que esto no es posible (es en C++ 11) así que traté SFINAE:?

template<typename T> 
typename std::enable_if<std::is_same<T, float>::value, bool>::type B<T>::what() 
{ 
    return true; 
} 

template<typename T> 
typename std::enable_if<!std::is_same<T, float>::value, bool>::type B<T>::what() 
{ 
    return false; 
} 

Esto también no funciona, no tengo ni idea de por qué, sin embargo, ¿alguien? Así que encontré this thread y terminó con:

template<typename T, typename Q> 
struct B : public A 
{ 
    virtual bool what() 
    { 
     return whatimpl(std::is_same<T, float>()); 
    } 

    bool whatimpl(std::false_type) 
    { 
     return false; 
    } 

    bool whatimpl(std::true_type) 
    { 
     return true; 
    } 
}; 

Esta solución final funciona, pero por qué no funciona el enable_if técnica? También estoy muy abierto a las sugerencias de una respuesta más clara que todavía no he encontrado.

Simplifiqué mis ejemplos tanto como sea posible - en mi caso de uso real, no se llama what()lo y de hecho lo hace un poco de trabajo, y querré 'especializarse' en un tipo definido por el usuario, no float.

+1

@Nawaz Me di cuenta de eso, pero esto es solo un caso simplificado para mostrar lo que estoy tratando de hacer :) Lea la última línea de la publicación. – David

+0

_what_ no es un método de plantilla, para anular A :: what() debe ser un único método no plantilla de la plantilla de clase B. No puede especializar el método sin plantilla, ni con enable_if ni con ningún otro techique. Sin embargo, usted puede especializar toda la clase B – user396672

+0

@ user396672 Entonces, ¿por qué funciona esto (especialización completa en lugar de parcial): 'plantilla <> bool B :: what() { return false; } ' – David

Respuesta

7

especialización parcial está explícitamente permitido por la norma sólo para plantillas de clase (véase 14.5.5 plantilla de clase especializaciones parciales)

Para los miembros de la plantilla de clase solo se permite la especialización explícita.

14,7 (3) dice:

Una especialización explícita puede ser declarada por una plantilla de función, una plantilla de clase, un miembro de una clase de plantilla o una plantilla miembro. Se introduce una declaración explícita de especialización por plantilla <>.

Así que cualquier definición a partir de

template<typename T> 

no es una sintaxis permitido para el miembro de la especialización de plantilla de clase.

[editar]

En cuanto a SFINAE intento, fallido, porque en realidad no hay ni sobrecargas ni especializaciones aquí (SFINAE funciona mientras se define un conjunto de funciones candidatas para la resolución de sobrecarga o al elegir la especialización adecuada). lo() está declarada como un único método de plantilla de clase y debe tener una definición única, y esta definición debe tener una forma:

template<typename T, typename Q> 
B<T,Q>:: bool what(){...} 

o puede ser también especializado explícitamente para particular, la instanciación de clase B:

template<> 
B<SomeParticularTypeT,SomeParticularTypeTypeQ>:: bool what(){...} 

Cualquier otro formulario no es sintácticamente válido, por lo que SFINAE no puede ayudarlo.

+0

Gracias, esto explica el primer intento fallido. ¿Alguna idea sobre el intento SFINAE? – David

+0

@Dave: SFINAE abrevia "La falla de ESPECIALIZACIÓN no es un error", por lo que es solo una técnica particular para _especialización_. Comenzando con la plantilla ... trataste de especializar parcialmente un método de plantilla de clase simplemente usando una forma más complicada. – user396672

+0

@Dave :: ... o la plantilla puede iniciar el método _definition_ para la plantilla de clase B , pero en este caso no es una especialización en absoluto y SFINAE tampoco funciona. – user396672

2

¿Por qué no cambiar a ..

template<typename T, typename Q> 
struct B : public A 
{ 
    bool what() 
    { 
     return false; //Or whatever the default is... 
    } 
}; 

template<typename Q> 
struct B<float, Q> : public A 
{ 
    bool what() 
    { 
     return true; 
    } 
}; 
+3

Porque B es una clase gigante y no quiero copiar/pegar una clase gigante 15 veces para cada especialización de 'what()' – David

+0

@Dave: ... aunque puedes heredar de una clase gigante intermedia añadiendo solo qué () anular en la clase final. – user396672

+0

@ user396672 Solo podría hacer eso si agregué una clase extra en la herencia, tenga en cuenta que A no tiene plantillas, por lo que la funcionalidad de B realmente no se pudo poner allí. La clase adicional necesitaría ser modelada e ir entre A y B. Podría escribirse como otra respuesta para responder a otras técnicas para manejar esto – David

Cuestiones relacionadas