如何根据精度轻松模板化数学函数

How to easily templatize math functions based on precision?

本文关键字:函数 何根 精度      更新时间:2023-10-16

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

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(,没有预构建的重载。

多亏了 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,则可以针对doublefloat专用化或重载foo,并让这些专用化/重载调用正确的函数。

我想你正在使用C函数。如果您改用 C++ 函数(C++有重载(,则无需玩任何技巧:

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

所以痛点是我实际上需要支持 4 种类型:浮点数, 双人间、complex_float、complex_double

如果你必须使用 c 函数,那么你可以编写一个包装器。编写一个与正确的 C 函数不同的sqrt

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

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

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

以及您需要的类似重载。