在模板中比较==!=

Mic*_*ndr 3 c++ comparison templates floating-accuracy

在模板类中执行==和!=运算符的正确方法是什么?假设这段代码:

template<typename T>
class C {
        T x, y;

        public:
        C(T a, T b) : x(a), y(b) {}

        bool cmp() {
                return x == y;
        }

};

int main()
{
        // OK
        C<int> i(1,2);
        i.cmp();

        // not OK
        C<double> d(1.0, 2.0);
        d.cmp();

        return 0;
}
Run Code Online (Sandbox Code Playgroud)

如果你用g ++ -Wfloat-equal构建它,你就会得到

警告:将浮点数与==或!=进行比较是不安全的[-Wfloat-equal]

因为你不能简单地比较浮点变量.


更新

我已经使用type_traits和enable_if解决了这个问题(感谢@Andrew和@OMGtechy):

#include <type_traits>
#include <limits>
#include <cmath>
#include <iostream>

using namespace std;

template <typename IntegralType>
typename std::enable_if<std::is_integral<IntegralType>::value, bool>::type
equal(const IntegralType& a, const IntegralType& b) {
        return a == b;
}

template <typename FloatingType>
typename std::enable_if<std::is_floating_point<FloatingType>::value, bool>::type
equal(const FloatingType& a, const FloatingType& b) {
        return std::fabs(a-b) < std::numeric_limits<FloatingType>::epsilon();
}

template<typename T>
class C {
    T x, y;

    public:
    C(T a, T b) : x(a), y(b) {}

    bool cmp() {
        return equal(x, y);
    }

};

int main()
{
    // OK
    C<int> i(1,2);
    cout << i.cmp() << endl;

    // not OK
    C<double> d(1.0, 1.0);
    cout << d.cmp() << endl;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

And*_*rew 6

这个问题似乎要问两件事:

  1. 如何在不使用operator ==的情况下进行浮点比较
  2. 如何根据传递给它的类型修改模板的行为.

第二个问题的一个答案是使用类型特征.下面的代码针对您的情况演示了这一点,为一般类型(使用==)提供了comparison_traits,并使用容差(也回答了第一个问题)为双打提供了专门化.

#include <cmath>

template <typename T> struct comparison_traits {
  bool equal(const T& a, const T& b) {
    return a == b;
  }

  // etc.
};

template<> struct comparison_traits<double> {
  bool equal(const double& a, const double& b) {
    return fabs(a - b) < 1e-15; // or whatever...
  }
};

template <typename T>
class C {
  T x, y;

  public:
    C(const T& a, const T& b) : x(a), y(b) {}

    bool cmp() {
      return comparison_traits<T>::equal(x, y);
    }
};

int main() {
  // OK
  C<int> i(1, 2);
  i.cmp();

  // Now OK too...
  C<double> d(1.0, 2.0);
  d.cmp();

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

其他选择包括:

  • 提供允许您指定比较函数的模板参数,默认为std :: equal_to

  • 将您的模板专门用于double,以便您可以编写不同的cmp()实现

  • 您可以使用类型特征为所有浮点类型执行此操作,而不是单独使用double和float (2认同)