enable_if method specialization

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

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

How can I use enable_if to make the following specialization happen for any floating point type (is_floating_point)?

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

EDIT: Here's an answer I came up which is different from the ones posted below...

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

Like the below posters say, using enable_if may not be ideal for this problem (it's very difficult to read)

3 Answers

With C++20

You can achieve that simply by adding requires to restrict the relevant template function:

template<typename Q> // the generic case, no restriction
A<T> operator% ( const Q& right ) const {
    return A<T>(std::fmod(x, right));
}

template<typename Q> requires std::is_integral_v<T> && std::is_integral_v<Q>
A<T> operator% ( const Q& right ) const {
    return A<T>(x % right);
}

The requires clause gets a constant expression that evaluates to true or false deciding thus whether to consider this method in the overload resolution, if the requires clause is true the method is preferred over another one that has no requires clause, as it is more specialized.

Code: https://godbolt.org/z/SkuvR9

Related