C++ 比较==!=在模板中

C++ 比较==!=在模板中,c++,templates,comparison,floating-accuracy,C++,Templates,Comparison,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&

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

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;
}
模板
C类{
tx,y;
公众:
C(ta,tb):x(a),y(b){}
布尔cmp(){
返回x==y;
}
};
int main()
{
//嗯
CⅠ(1,2);
i、 cmp();
//不好
cd(1.0,2.0);
d、 cmp();
返回0;
}
如果您使用g++-Wfloat equal构建它,您将得到

警告:将浮点与==或!=进行比较不安全 [-Wfloat相等]


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


更新 我已经用type_traits和enable_解决了这个问题,如果是这样的话(谢谢@Andrew和@OMGtechy):

#包括
#包括
#包括
#包括
使用名称空间std;
模板
typename std::enable_if::type
相等(常数积分类型&a、常数积分类型&b){
返回a==b;
}
模板
typename std::enable_if::type
相等(常量浮动类型&a、常量浮动类型&b){
返回std::fabs(a-b)cout这取决于如何使用它。正确比较浮动取决于上下文

我推荐@Niall所说的:添加一个comparator模板参数,默认值为
std::equal_to
。这将允许调用方控制值的比较方式。例如,请参阅
std::sort
上的文档,以了解如何使用comparator参数。其缺点是调用方有责任解释比较
float
s。如果他们忘记了,那么他们将得到您看到的编译器警告


另一个选项是模板类专门化。为您的类专门化以处理
float
double
类型,并使用您喜欢的逻辑对它们进行不同的比较。这可能不是最好的解决方案。这样做的好处是,调用方不再需要记住指定比较器或者。

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

  • 如何在不使用运算符==、和的情况下进行浮点比较
  • 如何根据传递给模板的类型修改模板的行为
  • 第二个问题的一个答案是使用类型特征。下面的代码针对您的情况演示了这一点,为一般类型(使用==)提供了比较特征,并使用公差(也回答了第一个问题)为双打提供了专门化

    #包括
    模板结构比较{
    布尔相等(常数T&a、常数T&b){
    返回a==b;
    }
    //等等。
    };
    模板结构比较{
    布尔值相等(常数双精度a、常数双精度b){
    return fabs(a-b)<1e-15;//或者其他什么。。。
    }
    };
    模板
    C类{
    tx,y;
    公众:
    C(常数T&a,常数T&b):x(a),y(b){}
    布尔cmp(){
    返回值:相等(x,y);
    }
    };
    int main(){
    //嗯
    CⅠ(1,2);
    i、 cmp();
    //现在也好了。。。
    cd(1.0,2.0);
    d、 cmp();
    返回0;
    }
    
    其他选择包括:

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

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


    如果您询问为什么会收到此警告:

    这里有一些例子:

    double a,b;
    a=10.0/13.0;
    b = a/3;
    b*=3;
    
    std::cout<<"a="<<a<<std::endl;
    std::cout<<"b="<<b<<std::endl;
    if(a!=b){
        std::cout<<"NOT  equal!!"<<std::endl;
        std::cout<<"a-b="<<a-b<<std::endl;
    }
    else
        std::cout<<"equal"<<std::endl;
    
    因为它不太准确,所以对double的适当比较应该定义一些公差:

    例如(公差可能根据需要而变化):


    如果您关心的类型没有适当的<代码>运算符==/COD>,请考虑将一个参数添加到要使用的比较器的模板中(然后默认为“<代码> STD::均等到”)。这与比较浮点值有很大关系,但实际上与模板无关。正确与否取决于用例。您希望浮点在这里发生什么情况?在某些情况下,
    =
    使用浮点值非常合适。对于其他情况,检查近似值是正确的。@Biffen实际上,我认为这是一个尝试od问题。如何实现该模板,使其处理包括浮点值在内的所有类型?“您不能简单地比较浮点变量”-是的,你可以。你不能依赖数学上等价的计算来给出完全相等的结果。你可以使用类型特征来处理所有浮点类型,而不是专门处理double和float。尽管如此,我还是想非常接近问题中的示例。另外,将一些事情保留为读者练习:)
    #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;
    }
    
    double a,b;
    a=10.0/13.0;
    b = a/3;
    b*=3;
    
    std::cout<<"a="<<a<<std::endl;
    std::cout<<"b="<<b<<std::endl;
    if(a!=b){
        std::cout<<"NOT  equal!!"<<std::endl;
        std::cout<<"a-b="<<a-b<<std::endl;
    }
    else
        std::cout<<"equal"<<std::endl;
    
    a=0.769231
    b=0.769231
    NOT  equal!!
    a-b=-1.11022e-016
    
    int compare(double a, double b)
    {
        double tolerancy = 0.000001;
        if (abs(a-b) < tolerancy) return 0;
        else if (a>b) return 1;
        else /*if (a<b)*/ return -1;
    } 
    
    a=0.769231
    b=0.769231
    equal