所有
所以,我创建了一个Comparable基类(一个Java),它完成了在C ++中重载比较运算符的工作。这是:
template <class T>
class Comparable {
public:
bool operator== (const T& rhs) const { return this->compare(rhs) == 0; }
bool operator!= (const T& rhs) const { return !(*this == rhs); }
bool operator< (const T& rhs) const { return this->compare(rhs) < 0; }
bool operator<= (const T& rhs) const { return (*this == rhs) || (*this < rhs); }
bool operator> (const T& rhs) const { return this->compare(rhs) > 0; }
bool operator>= (const T& rhs) const { return (*this == rhs) || (*this > rhs); }
protected:
virtual int compare (const T& rhs) const = 0;
};
子类对象既有ID,也有需要作为排序键的数据。我已经实现了每个,以便具有相同ID的对象返回0,如果它们不是相同的ID,则根据它们的数据进行排序。这是一个例子:
int Foo::compare(const Foo& rhs) const
{
if (_id == rhs._id)
return 0;
// _value is integer data; comparison should sort on this
if (_value == rhs._value)
{
// OK, same data, now sort on ID's
return _id.compare(rhs._id);
}
// Sort on value
return _value - rhs._value;
}
到目前为止,我觉得很好。
但是,当我尝试将Foo对象存储在std :: set容器中时,该集合不会消除重复。也就是说,它中仍然会有包含相同ID的对象,即使它应该被认为是相同的。
有谁知道发生了什么事?
编辑:关于代码设计的原因有很多问题。
我需要满足两个条件:
这是因为创建这些对象的数据来自未经验证的来源。如果该源为具有相同ID但具有不同值的数据提供数据,则该数据无效。
编辑2:关于std :: map的严格弱排序。假设你有两个Foo对象,A和B.
如果他们的ID相等,那么A&lt; B是假的,B&lt; A是假的。 如果他们的ID不相等,那么A&lt; B取决于它们的值是真还是假,并且B
这不符合严格的订购规则吗?
在任何情况下,如果std :: set使用小于运算符(默认情况下),它是否应该按设计工作?
编辑3:std::set
,而非std::map
。那真是我的愚蠢。道歉。
答案 0 :(得分:4)
std::map
无法通过operator==
确定重复项。它使用operator<
1 ,因为它无论如何都需要使用它来确定顺序。您的operator<
已损坏。它需要强制执行strict weak ordering。
比较失败的方式是以下属性(称为传递性)。对于3个对象,如果A < B
和B < C
,则必须是A < C
。
因此,请考虑三个对象A
,B
和C
。 A.id != B.id
,A.value < B.value
,A < B
。C.id == B.id
。现在,C.id != A.id
(因此C.value < A.value
),但C < A
。所以A < B
和C
。因此,< B
应为C.id == B.id
。但事实并非如此,因为compare
。
这样做的一种方法是定义int Foo::compare(const Foo& rhs) const
{
if (_id < rhs._id)
return -1;
if (rhs._id < _id)
return 1;
return _value - rhs._value;
}
函数,如下所示:
std::map
如果您无法使用它,并且找不到其他方法来强制执行正确的排序,那么您根本无法将对象用作{{1}}中的键。
<子> 1。如果rhs不小于lhs,并且lhs不小于rhs,那么暗示它们是相等的。您还可以提供替代仿函数,只要它还强制执行严格的弱序排序。
答案 1 :(得分:3)
如果您没有严格的弱订单,则不能使用map
,如果您这样做,则不能抱怨,但它不起作用。这是map
的前提条件。
编辑:
您的compare
未实现您指定的语义 - 如果您在第二次测试中_value == rhs._value
,则应返回0。
但是通过这个修复,你仍然没有一致的顺序 - 请参阅Benjamin Lindley在评论中给出的例子。基本上你的排序没有意义 - 你需要修复你的语义,或者停止使用需要一致排序的标准库组件。