enable_if method specialization

前端 未结 3 758
栀梦
栀梦 2020-12-28 20:36
template
struct A
{
    A operator%( const T& x);
};

template
A A::operator%( const T& x ) {          


        
相关标签:
3条回答
  • 2020-12-28 20:52

    Use overloading instead of explicit specialization when you want to refine the behavior for a more specific parameter type. It's easier to use (less surprises) and more powerful

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

    An example that uses SFINAE (enable_if) as you seem to be curious

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

    Way more ugly of course. There's no reason to use enable_if here, I think. It's overkill.

    0 讨论(0)
  • 2020-12-28 21:09

    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

    0 讨论(0)
  • 2020-12-28 21:11

    You can also use a default boolean template parameter like this:

    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);
        }
    };
    
    0 讨论(0)
提交回复
热议问题