enable_if方法专门化

Dav*_*vid 11 c++ boost tr1 template-specialization c++11

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

template<typename T>
A<T> A<T>::operator%( const T& x ) { ... }
Run Code Online (Sandbox Code Playgroud)

如何使用enable_if为任何浮点类型(is_floating_point)进行以下特化?

template<>
A<float> A<float>::operator%( const float& x ) { ... }
Run Code Online (Sandbox Code Playgroud)

编辑:这是我提出的答案,与下面发布的答案不同......

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);
    }
};
Run Code Online (Sandbox Code Playgroud)

如下面的海报所说,使用enable_if可能不是理想的问题(这很难阅读)

Joh*_*itb 30

如果要优化更具体的参数类型的行为,请使用重载而不是显式特化.它更容易使用(更少的惊喜)和更强大

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) { /* ... */ }
};
Run Code Online (Sandbox Code Playgroud)

使用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) { /* ... */ }
};
Run Code Online (Sandbox Code Playgroud)

当然更丑陋的方式.enable_if我认为没有理由在这里使用.这太过分了.

  • @Johannes您enable_if解决方案不编译我...`错误C4519:默认模板参数只能在类template`'错误C2535:"A <T> A <T> :: opModImpl(常量U&) ':已定义或声明的成员函数 (4认同)

Ami*_*rsh 6

使用 C++20

您只需添加requires限制相关模板函数即可实现此目的:

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);
}
Run Code Online (Sandbox Code Playgroud)

requires子句获取一个constant expression评估truefalse决定是否在重载决策中考虑该方法的方法,如果requires子句为真,则该方法优于另一个没有requires子句的方法,因为它更专业。

代码: https: //godbolt.org/z/SkuvR9


Pau*_* II 5

您还可以使用默认的布尔模板参数,如下所示:

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);
    }
};
Run Code Online (Sandbox Code Playgroud)