enable_if специализация метода - PullRequest
11 голосов
/ 08 июля 2011
template<typename T>
struct A
{
    A<T> operator%( const T& x);
};

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

Как я могу использовать enable_if, чтобы сделать следующую специализацию для любого типа с плавающей точкой (is_floating_point)?

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

РЕДАКТИРОВАТЬ: Вот ответ, который я пришел, который отличается от опубликованныхниже ...

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);
    }
};

Как говорят приведенные ниже плакаты, использование enable_if может быть не идеальным решением для этой проблемы (очень трудно читать)

Ответы [ 2 ]

29 голосов
/ 08 июля 2011

Используйте перегрузку вместо явной специализации, когда вы хотите уточнить поведение для более определенного типа параметра. Проще в использовании (меньше сюрпризов) и мощнее

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) { /* ... */ }
};

Пример, который использует SFINAE (enable_if), как вам кажется любопытным

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) { /* ... */ }
};

Конечно, намного страшнее. Думаю, здесь нет смысла использовать enable_if. Это излишне.

4 голосов
/ 17 августа 2014

Вы также можете использовать параметр логического шаблона по умолчанию, например:

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);
    }
};
...