2011-02-26 16 views
5

tengo un TPoint clase que se pondría en práctica con diferentes tipos de base de manerafunciones miembro sobrecargados para una plantilla determinada especialización

template<typename T>class tPoint{ 
    T x; 
    T y; 
public: 
    void Set(T ix, T iy){x=ix;y=iy;} 
}; 

Cuando el tipo T es int, tPoint<int>, quiero un conjunto especial (float, float) entonces puedo redondear los valores antes de la asignación.

pensé que con la especialización que pude:

template<> void tPoint<int>::Set(float ix,float iy){x=ix+.5; y=iy+.5;} 

De esta manera el compilador se queja de que no hay ninguna función de emparejamiento en la definición de clase.

Pero si me declaro en el conjunto de la clase (float, float), entonces se dice que ya está definido (cuando se compila para T = flotación)

espero sido claro, lo que sería un enfoque limpio para esto o estoy haciendo algo mal? ¡Gracias!

Respuesta

5

Usted necesidad de especializarse la clase, así:

template<> class tPoint<int>{ 
    int x; 
    int y; 
public: 
    void Set(int ix, int iy){x=ix;y=iy;} 
    void Set(float ix, float iy){x = ix+0.5; y = iy+0.5;} 
}; 
+0

me especializo la versión flotante en lugar de todo el flotador no uno :-) – AProgrammer

+0

@AProgrammer, el OP sólo se menciona que quieran especializarse para TPoint , pero acuerde si quiere el segundo "conjunto" para más de una clase. –

0

Uso impulso enable_if para evitar que la versión de flotación cuando instanciado con el flotador.

0

lo mejor es:

template<typename T>class tPoint{ 
    T x; 
    T y; 
public: 
    void Set(T ix, T iy) { set_impl(boost::type<T>(), x, y); } 
private: 
    void set_impl(boost::type<int>, float ...); 
    template<typename U> 
    void set_impl(boost::type<U>, T ...); 
}; 
0

Trate de no proporcionar la implementación predeterminada de Set() dentro de la clase. De esta forma, es más fácil especializarse para flotar.

3

El problema al que se enfrenta tiene que ver con T de pie ya sea para int o float.

Si nos fijamos en la definición de clase de plantilla, podrás notar que la misma T que aparece después de typename en la parte template aparece también como parámetro al método Set.

Esto significa que cuando se habla de Point<int> entonces sólo hay uno Set método definido, que tiene dos int. Y cada Point<T> diferente tendrá su propio método Set(T,T).

Si usted desea para una Set método diferente, entonces tiene que declarar una plantilla Set dentro de la clase de plantilla, esto se hace de la siguiente manera:

template <typename T> 
class Point 
{ 
public: 
    template <typename Num> 
    void Set(Num x, Num y); 
}; 

Nota cómo tuviera que elegir un nombre de parámetro de plantilla diferente .


Con el fin de resolver el problema, se podría introducir otro método, por float, pero entonces tendría que tener otro para double, y long double ... Es muy pronto va a ser difícil.

La solución más simple, es ir de fuerza bruta:

template <typename Integral> 
template <typename Num> 
void Point<Integral>::Set(Num x, Num y) 
{ 
    this->x = long double(x) + 0.5; 
    this->y = long double(y) + 0.5; 
} 

Para int y otros, sobre todo es inútil, pero funciona. Para los puntos flotantes, usamos el tipo de coma flotante más grande disponible para evitar perder precisión y luego realizamos el redondeo.

Obviamente, no funciona si de repente queremos un Point<float>, por lo tanto, necesitamos una solución más inteligente, basada en los rasgos de tipo. La clase std::numeric_limits<T> tiene un is_integer que precisa si se trata o no de un tipo integral.

template <typename T> 
template <typename Num> 
void Point<T>::Set(Num x, Num y) 
{ 
    if (std::numeric_limits<T>::is_integer && 
    !std::numeric_limits<Num>::is_integer) 
    { 
    this->x = x + 0.5; 
    this->y = y + 0.5; 
    } 
    else 
    { 
    this->x = x; 
    this->y = y; 
    } 
    } 
} 

Sé que parece estúpida utilizar un if de algo que podría ser determinado en tiempo de compilación ... pero no se preocupen, el compilador es suficientemente inteligente como para hacer figura hacia fuera en de compilación tiempo y optimizar la distancia if y la rama sin usar por completo;)

+0

Gracias, es más complejo de lo que esperaba, pero su publicación tiene algunos puntos interesantes para un principiante en la especialización de plantilla – Joan

Cuestiones relacionadas