区分模板中的整数和浮点类型

Distinguishing integer from floating point types in a template

本文关键字:类型 整数      更新时间:2023-10-16

我想对几种整数类型(16、32、64 位)和浮点类型(浮点数、双精度数、长双精度数)执行类似但不相同的计算。大多数代码是相同的,但对于整数和浮点数,某些部分需要以不同的方式完成。例如,比较整数可以用 a==b 来完成,而比较浮点数应该用 abs(a-b) 来完成

一种方法是将整数和浮点数之间不同的代码部分隔离为小函数,并为每种类型专门化模板。但是,我宁愿不为每个整数类型复制粘贴相同的代码,不为每个浮点类型复制粘贴另一个代码。因此问题来了:是否可以同时将模板功能专门化为多种类型?语义类似于以下内容的东西,如果它是合法的:

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;
}

使用 C++11 可以使用类型特征。请参阅std::enable_if文档在您的情况下,它可能如下所示:

函数参数专用化:

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;
}

返回类型专用化:

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;
}

是的,您可以将 SFINAE 与 <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();
}

你可以专注于<type_traits>

然后,您可以根据类别对功能进行分组

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);
};