如何创建一个 class 专业化来为浮点数和整数做不同的事情?

How to create a class specialization that does different things for floats and ints?

我想创建一个名为 Vec2 的结构,它看起来像这样:

template<typename T>
struct Vec2 {
  T x, y;

  // Other things are also there like Constructors, Destructors, operator overloads, etc.
};

我希望能够为 % 运算符创建运算符重载。重载看起来像这样

Vec2<T> operator%(const Vec2<T> &other) {
  return Vec2<T>(this-> x % other.x, this.y % other.y);
}

现在的问题是,如果有人使用 float 模板参数实例化此结构,则此运算符重载会中断,因为您无法使用 C++ 中的默认 % 运算符对浮点数取模。所以在那种情况下我想改用这个函数。

Vec2<T> operator%(const Floating &other) {
  return Vec2<T>(fmod(this->x, other.x), fmod(this->y, other.y));
}

那么我该怎么做,如果有人用 float 作为模板参数实例化这个结构,那么他们应该可以访问第二个运算符重载,否则是第一个。

我已经成功地创建了一个模板来帮助我过滤掉所有像这样的浮点模板参数

template<typename T,
         typename  = std::enable_if_t<std::is_floating_point_v<Integral>>>
struct Vec2 {
  T x, y;

  // Other things are also there like Constructors, Destructors, operator overloads, etc.
  Vec2<T> operator%(const Vec2<T> &other) {
    return Vec2<T>(fmod(this->x, other.x), fmod(this->y, other.y));
  }
};

这使得没有人可以用积分值实例化此 class。但我不希望这种情况发生。我希望他们也能够使用 Integral 值实例化此 class,只是使用不同的成员函数。怎样才能做到这一点?我试过做一些部分专业化,但没有成功。

注意:我的实际代码结构略有不同,基础 class 包含所有常用代码,但为了简单起见,我没有在此处包含它。

我正在使用 GCC 11.1.0。 C++ 标准并不重要,因为我什至可以使用 C++20。

在这种情况下,一个简单的 if constexpr 就足够了:

Vec2<T> operator%(const Vec2<T> &other) 
{
    if constexpr (std::is_floating_point_v<T>)
    {
        return Vec2<T>(fmod(this->x, other.x), fmod(this->y, other.y));
    }
    else 
    {
        return Vec2<T>(this-> x % other.x, this->y % other.y);
    }
}

这里我用std::is_floating_point_v在编译时判断T是否是任何浮点类型。两个分支中只有一个将出现在各自的模板实例化中。

我认为这比为 float/non-float 专门化整个模板要简单得多,而且在我看来比 SFINAE 更具可读性。