在模板中比较 == !=
Comparing == != in templates
在模板类中执行 == 和 != 运算符的正确方法是什么?假设以下代码:
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;
}
如果你用 g++ -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;
}
这个问题似乎在问两件事:
- 如何在不使用运算符==的情况下进行浮点比较,以及
- 如何根据传递给模板的类型修改模板的行为。
第二个问题的一个答案是使用类型特征。下面的代码针对您的情况演示了这一点,为常规类型(使用 ==)提供了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;
}
其他选项包括:
提供一个模板参数,允许您指定比较函数,默认为 std::equal_to
将模板专用化为 double,以便您可以编写不同的 cmp() 实现
这取决于它将如何使用。正确比较浮点数取决于上下文。
我会推荐@Niall所说的:添加一个比较器模板参数,默认为 std::equal_to
.这将允许调用方控制如何比较值。例如,请参阅有关std::sort
的文档,以了解比较器参数的使用方式。这样做的缺点是,调用方有责任考虑比较float
。如果他们忘记了,那么他们会收到您看到的编译器警告。
另一种选择是模板类专用化。为您的班级专门处理float
或double
类型,并使用您喜欢的任何逻辑以不同的方式比较它们。可能不是最好的解决方案。这样做的好处是,调用方不再需要记住指定比较器。
如果你问为什么收到这个警告:
这里有一些例子:
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和B显然是相等的。但这是我得到的输出:
a=0.769231
b=0.769231
NOT equal!!
a-b=-1.11022e-016
因为它不是那么准确,所以对 double 的正确比较应该定义一些容忍度:
例如(容忍度可能会根据需要而改变):
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
- 比较并显示使用最小值(a,b)和最大值(a、b)升序排列的4个数字
- 为什么比较运算符如此快速
- 我可以使用 g++ 进行三种比较 (<=>) 吗?
- 比较字符数组
- 将模板化的类型与C++中的某些类/类型进行比较
- C++自定义比较函数
- 如何比较自定义类的std::变体
- 多个If语句与使用逻辑运算符计算条件的单个语句的比较
- std::设置自定义比较器
- 布尔比较运算符是如何在C++中工作的
- C++将目录中的所有文件与::filesystem进行比较
- shell排序中的交换和比较
- 如何在C++中比较两个char数组
- catch框架有没有办法比较流或文件
- 从文件中读取多个字节,并将它们存储在C++中进行比较
- 智能指针作为无序映射键,并通过引用进行比较
- 比较if语句中的数组值和int值
- 对于循环变体比较
- 使用自定义比较函数使用std::sort()对矢量字符串进行排序时出现问题
- 比较两个大小不等的映射c++