2009-10-01 23 views
23

¿Es posible especializar miembros particulares de una clase de plantilla? Algo como:¿Especialización de plantilla de miembros particulares?

template <typename T,bool B> 
struct X 
{ 
    void Specialized(); 
}; 

template <typename T> 
void X<T,true>::Specialized() 
{ 
    ... 
} 

template <typename T> 
void X<T,false>::Specialized() 
{ 
    ... 
} 

Por supuesto, este código no es válido.

+0

No está del todo claro qué quiere decir aquí. ¿Quiere decir forzar que el parámetro de la plantilla sea el descendiente de un cierto tipo? Al igual que en Java con ? –

+1

@Alcon Cuando se especializa en una clase de plantilla, debe proporcionar una implementación * diferente * para toda la clase. Me parece que quiere compartir códigos comunes entre especializaciones, excepto algunas funciones. – AraK

+0

¿Debería esta pregunta decir "función miembro" en lugar de "miembro"? Para que nadie piense que esto se trata de miembros de datos. –

Respuesta

3

Esto es lo que me ocurrió, no está tan mal :)

//The generic template is by default 'flag == false' 
template <class Type, bool flag> 
struct something 
{ 
    void doSomething() 
    { 
     std::cout << "something. flag == false"; 
    } 
}; 

template <class Type> 
struct something<Type, true> : public something<Type, false> 
{ 
    void doSomething() // override original dosomething! 
    { 
     std::cout << "something. flag == true"; 
    } 
}; 

int main() 
{ 
    something<int, false> falseSomething; 
    something<int, true> trueSomething; 

    falseSomething.doSomething(); 
    trueSomething.doSomething(); 
} 
+5

No estás invalidando, solo te estás escondiendo. – curiousguy

26

Sólo puede especializarse explícitamente, proporcionando todos los argumentos de plantilla. No se permite ninguna especialización parcial para las funciones miembro de las plantillas de clase.

template <typename T,bool B> 
struct X 
{ 
    void Specialized(); 
}; 

// works 
template <> 
void X<int,true>::Specialized() 
{ 
    ... 
} 

Una solución es introducir funciones sobrecargadas, que tienen la ventaja de estar aún en la misma clase, por lo que tienen el mismo acceso a los miembros de variables, funciones y dispositivos de

// "maps" a bool value to a struct type 
template<bool B> struct i2t { }; 

template <typename T,bool B> 
struct X 
{ 
    void Specialized() { SpecializedImpl(i2t<B>()); } 

private: 
    void SpecializedImpl(i2t<true>) { 
     // ... 
    } 

    void SpecializedImpl(i2t<false>) { 
     // ... 
    } 
}; 

Nota que al pasar a las funciones sobrecargadas y al presionar los parámetros de la plantilla en un parámetro de función, puede arbitrariamente "especializar" sus funciones, y también puede templatarlas según sea necesario. Otra técnica común es aplazar a una plantilla de clase definido por separado

template<typename T, bool B> 
struct SpecializedImpl; 

template<typename T> 
struct SpecializedImpl<T, true> { 
    static void call() { 
    // ... 
    } 
}; 

template<typename T> 
struct SpecializedImpl<T, false> { 
    static void call() { 
    // ... 
    } 
}; 

template <typename T,bool B> 
struct X 
{ 
    void Specialized() { SpecializedImpl<T, B>::call(); } 
}; 

Me parece que por lo general requiere más código y me encuentro con la función de sobrecarga más fácil de manejar, mientras que otros prefieren la Defer a modo de plantilla de clase. Al final es una cuestión de gusto. En este caso, podría haber puesto esa otra plantilla dentro de X también como una plantilla anidada; en otros casos en los que explícitamente se especialice en lugar de solo parcialmente, entonces no puede hacerlo, porque puede colocar especializaciones explícitas solo en el ámbito del espacio de nombres. no en el alcance de la clase.

También puede crear una plantilla de tales SpecializedImpl sólo para propósito de sobrecarga de funciones (que entonces funciona de forma similar a nuestro i2t de antes), ya que la variante siguiente demuestra que sale de la primera variable de parámetro también (por lo que puede llamar con otro tipos - no sólo con los parámetros de plantilla de la creación de instancias de corriente)

template <typename T,bool B> 
struct X 
{ 
private: 
    // maps a type and non-type parameter to a struct type 
    template<typename T, bool B> 
    struct SpecializedImpl { }; 

public: 
    void Specialized() { Specialized(SpecializedImpl<T, B>()); } 

private: 
    template<typename U> 
    void Specialized(SpecializedImpl<U, true>) { 
     // ... 
    } 

    template<typename U> 
    void Specialized(SpecializedImpl<U, false>) { 
     // ... 
    } 
}; 

creo que a veces, se aplaza a otra plantilla es mejor (cuando se trata de casos tales como arreglos y apuntadores, la sobrecarga puede complicado y simplemente el reenvío a una plantilla de clase ha sido más fácil para mí en ese momento), y algunas veces simplemente sobrecargar dentro de la plantilla es mejor, especialmente si realmente argumentos de función de sala y si toca las variables de miembro de las clases.

+0

+1 Bonitas soluciones elegantes frente a mis ojos. – AraK

+0

gracias, apreciado :) –

+0

Ahora que C++ 11 está fuera, esto debería usar 'std :: integral_constant' me piensa. Me editaría, pero es una verdadera molestia en la vista móvil en iPod Touch ... – Xeo

Cuestiones relacionadas