2011-07-08 9 views
7
template<typename T> 
struct A 
{ 
    A<T> operator%(const T& x); 
}; 

template<typename T> 
A<T> A<T>::operator%(const T& x) { ... } 

¿Cómo puedo usar enable_if para hacer que la siguiente especialización suceda para cualquier tipo de coma flotante (is_floating_point)?especialización del método enable_if

template<> 
A<float> A<float>::operator%(const float& x) { ... } 

EDIT: Aquí es una respuesta que se me ocurrió que es diferente de los que publican a continuación ...

template<typename T> 
struct A 
{ 
    T x; 

    A(const T& _x) : x(_x) {} 

    template<typename Q> 
    typename std::enable_if<std::is_same<Q, T>::value && std::is_floating_point<Q>::value, A<T> >::type operator% (const Q& right) const 
    { 
     return A<T>(fmod(x, right)); 
    } 

    template<typename Q> 
    typename std::enable_if<std::is_convertible<Q, T>::value && !std::is_floating_point<Q>::value, A<T> >::type operator% (const Q& right) const 
    { 
     return A<T>(x%right); 
    } 
}; 

Al igual que los carteles por debajo decir, utilizando enable_if puede no ser ideal para este problema (es muy difícil de leer)

Respuesta

25

Utilice la sobrecarga en lugar de la especialización explícita cuando desee refinar el comportamiento para un tipo de parámetro más específico. Es más fácil de usar (menos sorpresas) y más potente

template<typename T> 
struct A 
{ 
    A<T> operator%(const T& x) { 
     return opModIml(x, std::is_floating_point<T>()); 
    } 

    A<T> opModImpl(T const& x, std::false_type) { /* ... */ } 
    A<T> opModImpl(T const& x, std::true_type) { /* ... */ } 
}; 

Un ejemplo que utiliza SFINAE (enable_if) como pareces ser curioso

template<typename T> 
struct A 
{ 
    A<T> operator%(const T& x) { 
     return opModIml(x); 
    } 

    template<typename U, 
      typename = typename 
       std::enable_if<!std::is_floating_point<U>::value>::type> 
    A<T> opModImpl(U const& x) { /* ... */ } 

    template<typename U, 
      typename = typename 
       std::enable_if<std::is_floating_point<U>::value>::type> 
    A<T> opModImpl(U const& x) { /* ... */ } 
}; 

manera más fea, por supuesto. No hay ninguna razón para usar enable_if aquí, creo. Es excesivo.

+0

Agradezco la respuesta y me gusta su solución, pero no estoy de acuerdo con la plantilla de por qué cree que la especialización es erróneo. Si es posible especializarse para múltiples tipos usando enable_if, aún me gustaría saber cómo – David

+0

@Dave porque puede usar sobrecarga en su lugar. Donde tiene un parámetro y quiere especializarse para tipos de parámetros, la sobrecarga es mejor. No, no puedes "especializarte con' enable_if' ". Lo que quieres decir es sobrecarga. Voy a agregar un ejemplo que sobrecarga y usa SFINAE. –

+0

Esto puede sonar estúpido, pero no me gusta que opModImpl esté allí, incluso si es privado. Además, no me gusta la idea de tener potencialmente un extra temporal creado allí, a pesar de que el optimizador debería deshacerse de él. C++ 0x debería haber incluido una forma de tener múltiples especializaciones usando la misma definición en primer lugar – David

2

También puede utilizar un parámetro booleano de plantilla por defecto de esta manera:

template<typename T> 
struct A 
{ 
    T x; 

    A(const T& _x) : x(_x) {} 

    template<bool EnableBool = true> 
    typename std::enable_if<std::is_floating_point<T>::value && EnableBool, A<T> >::type 
    operator% (const T& right) const 
    { 
     return A<T>(fmod(x, right)); 
    } 

    template<bool EnableBool = true> 
    typename std::enable_if<!std::is_floating_point<T>::value && EnableBool, A<T> >::type 
    operator% (const T& right) const 
    { 
     return A<T>(x%right); 
    } 
}; 
Cuestiones relacionadas