template
struct A
{
A operator%( const T& x);
};
template
A A::operator%( const T& x ) {
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.
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
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);
}
};