在运算符第一个参数上避免浮点数和非浮点数的模板运算符重载冲突

Avoiding Template operator overload collisions for float and non float on the operator first argument

我有一种情况,我的模板模数运算符在浮点数和整数类型之间表现得很好。 我记得有一种方法可以使它 select 比更广泛的范围更具体,但我似乎无法找到或记住如何做到这一点。

基本上我有 2 个冲突的方法(重新定义错误。)

我想做的是在其类型 (T_COORDS) 为浮点时使用专用模数运算符重载,当它不是浮点时使用更广泛的重载。

专门的(注意它使用数学 fmod 函数):

template <size_t N
    , enable_if_t<N != 0 && N <= C_COORDS*N_COORDS && N % C_COORDS == 0, bool> = false>
friend Coords operator % (const Coords<float,C_COORDS,N_COORDS>& coords0, const auto (& coords1)[N])
{
  Coords<float,C_COORDS,N_COORDS> result = coords0;
  for (int i=0; i < C_COORDS*N_COORDS; i++)
      result.coords[i] = fmod(result.coords[i], coords1[i%N]);
  return result;
}

更广泛的(注意它使用标准浮点模数):

template <std::size_t N
    , std::enable_if_t<N != 0 && N <= C_COORDS*N_COORDS && N % C_COORDS == 0
    , bool> = false>
friend Coords operator % (const Coords<T_COORDS,C_COORDS,N_COORDS>& coords0, const auto (& coords1)[N])
{
  Coords<T_COORDS,C_COORDS,N_COORDS> result = coords0;
  for (int i=0; i < C_COORDS*N_COORDS; i++)
      result.coords[i] %= coords1[i%N];
  return result;
}

这些重载包含在模板 class 定义中:

template <class T_COORDS, size_t C_COORDS, size_t N_COORDS>
class Coords {
public:

  T_COORDS coords[C_COORDS*N_COORDS];

  // (body in here)

};

T_COORDS 是一个 class 模板参数,而不是函数模板参数,这意味着它对部分排序没有影响,因为更通用的函数无论如何都是用 T_COORDS=float 实例化的,因此它与 float 完全相同。但是,您可以从重载解析中禁用该函数,利用它已经具有一些依赖于直接上下文的 enable_if 条件的事实:

template <std::size_t N
        , std::enable_if_t<N != 0 && N <= C_COORDS*N_COORDS && N % C_COORDS == 0
                           && !std::is_same<T_COORDS, float>{}
                           // ~~~~~~~~~~~~^
        , bool> = false>
friend Coords operator %(const Coords<T_COORDS, C_COORDS, N_COORDS>& coords0
                       , const auto (& coords1)[N]);

我无法理解你的逻辑,但如果你想让你的函数行为根据类型是否为 double 发生变化,你可以使用类似下面的内容..

#include <type_traits>
#include <iostream>
template <class T>
void func(){
    constexpr static bool isFloat = std::is_floating_point<T>::value;//static in classes
    if (isFloat) std::cout << "f\n";//u can use fmod() here
    else std::cout << "i\n";//use regular % here
}
int main(){
    func<int>();
    func<double>();
}

我只保留其中一个重载,但将其 for 循环更改为:

for (int i=0; i < C_COORDS*N_COORDS; i++)
    result.coords[i] = my_mod(result.coords[i], coords1[i%N]);

像这样定义 my_mod 之后(在外部范围内):

template <typename T>
T my_mod(const T& x, const T& y) { return x % y; }

float my_mod(float x, float y) { return fmod(x, y); }
// maybe define it for double as well