Michael
Michael

Reputation: 5939

Distinguishing integer from floating point types in a template

I'd like to perform similar, but not identical computations for several integer types (16, 32, 64 bits) and floating point types (float, double, long double). Most of the code is identical, but some portions need to be done differently for ints and floats. For example, comparing ints can be done with a==b, while comparing floats should be done with abs(a-b)

One way to do that would be to isolate the parts of code that are different between ints and floats into small functions and specialize template for each type. However, I'd rather not to copy-paste identical code for each of the integer types and another code for each of the float types. Thus the question: is it possible to specialize template function for multiple types at once? Something semantically similar to the following if it was legal:

template<>
bool isEqual< short OR long OR long long >( T a, T b ) { 
    return a == b;
}

template<>
bool isEqual< float OR double OR long double >( T a, T b ) { 
    return abs( a - b ) < epsilon;
}

Upvotes: 6

Views: 5794

Answers (3)

sbabbi
sbabbi

Reputation: 11191

Yes, you can use SFINAE in combination with the metafunctions from <type_traits>

#include<type_traits>

template<class IntegralType>
typename std::enable_if<
    std::is_integral<IntegralType>::value,
    bool>::type

isEqual(IntegralType a,IntegralType b)
{
    return a == b;
}

template<class FloatingType>
typename std::enable_if<
    std::is_floating_point<FloatingType>::value,
    bool>::type

isEqual(FloatingType a,FloatingType b)
{
    return fabs(a-b) <  std::numeric_limits<FloatingType>::epsilon();
}

Upvotes: 4

Glenn Teitelbaum
Glenn Teitelbaum

Reputation: 10343

You can specialize on <type_traits>

Then you can group functions based on categories

template<typename T, bool INTEGRAL> class isEqualbyType;

template<typename T>
class isEqualbyType<T, true>
{
public:
    static bool cmp( T a, T b ) { 
        return a == b; }
};

template<typename T>
class isEqualbyType<T, false>
{
public:

    static bool cmp( T a, T b ) {
        static const double epsilon=1e-50;
        return abs( a - b ) < epsilon; }
};

template<typename T>
bool isEqual( T a, T b )
{
   return isEqualbyType<T, std::is_integral<T>::value>::cmp(a,b);
};

Upvotes: 2

Erbureth
Erbureth

Reputation: 3423

With C++11 it is possible to use type traits. See std::enable_if documentation In your case, it might look like this:

Function parameter specialization:

template<class T>
bool isEqual(T a, T b, typename std::enable_if<std::is_integral<T>::value >::type* = 0) 
{
    return a == b;
}

template<class T>
bool isEqual(T a, T b, typename std::enable_if<std::is_floating_point<T>::value >::type* = 0) 
{
    return abs( a - b ) < epsilon;
}

Return type specialization:

template<class T>
typename std::enable_if<std::is_integral<T>::value, bool >::type isEqual(T a, T b)

{
    return a == b;
}

template<class T>
typename std::enable_if<std::is_floating_point<T>::value, bool >::type isEqual(T a, T b)
{
    return abs( a - b ) < epsilon;
}

Upvotes: 18

Related Questions