如何轻松地基于精度对数学函数进行模板化?

时间:2019-02-07 19:59:59

标签: c++

假设我有两个已经预先定义的数学函数:

float sqrtf(float a);
double sqrt(double a);

我有一些用C ++编写的模板化代码,我想在两者之间自动切换:

template<typename Precision>
void foo(Precision arg) {
    sqrt<Precision>(arg); // Call into sqrtf or sqrt depending on type?
}

是否有一种简便的方法可以完成上述操作而不必手动重写所有重载?

为清楚起见进行编辑:这些是C和CUDA函数(例如BLAS),没有预先建立的重载。

3 个答案:

答案 0 :(得分:5)

感谢C ++ 17的if constexpr,它非常简单

template <typename...>
struct always_false { static constexpr bool value = false; };  // used to make the static_asset value a dependent value otherwise it always fires

template<typename Precision>
void foo(Precision arg) {
    if constexpr (std::is_same_v<Precision, double>)
        sqrt(arg);
    else if constexpr (std::is_same_v<Precision, float>)
        sqrtf(arg);
    else
        static_assert(always_false<Precision>::value, "foo can only be called with the types double or float");
}

如果您不能使用C ++ 17,则可以为foodouble专门化或重载float,并让那些专门化/重载调用正确的函数。

答案 1 :(得分:2)

我想您正在使用C functions。如果您改用C++ functions(C ++具有重载),则不需要玩任何花招:

template<typename Precision>
void foo(Precision arg) {
   std::sqrt(arg); // Calls the right overload depending on type of arg
}
  

因此,痛苦的是我实际上需要支持4种类型:浮动,   double,complex_float,complex_double

如果必须使用c函数,则可以编写包装器。编写一个sqrt,它可以分配给正确的C函数:

template <typename T>
T my_sqrt(T x);

template<>
float my_sqrt(float x) { return sqrtf(x); }

以及其他三种类型的类似专业。然后在foo中调用该包装器

template<typename Precision>
void foo(Precision arg) {
    my_sqrt(arg);
}

答案 2 :(得分:0)

在C ++ 17之前,您可以编写调用相应函数的模板专业化版本:

template<class NumericType>
typename std::enable_if<std::is_same<NumericType, double>::value, void>::type foo(const NumericType number) {
  return sqrt(number);
}

以及您需要的类似重载。