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对于这个问题可能并不理想(这很难阅读)
答案 0 :(得分:29)
如果要优化更具体的参数类型的行为,请使用重载而不是显式特化。它更容易使用(更少的惊喜)和更强大的
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
。这太过分了。
答案 1 :(得分:4)
您还可以使用默认的布尔模板参数,如下所示:
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);
}
};
答案 2 :(得分:2)
您只需添加 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);
}
requires
子句获得一个constant expression
,其求值为true
或false
,从而决定是否在过载解析中考虑此方法,如果require子句为true,则该方法比另一种没有require子句的方法更可取,因为它更加专门。