我很难正确设置比较。 以下是我的问题示例,我的代码错误地假定{1,2} = {2,1}:http://ideone.com/i7huL
#include <iostream>
#include <map>
using namespace std;
struct myStruct {
int a;
int b;
bool operator<(const myStruct& rhs) const {
return rhs.a < this->a && rhs.b < this->b;
}
};
int main() {
std::map <myStruct, int> mymap ;
myStruct m1={1,2};
myStruct m2={2,1};
mymap.insert(make_pair(m1,3));
std::map<myStruct, int>::iterator it1 = mymap.find(m1);
std::map<myStruct, int>::iterator it2 = mymap.find(m2);
cout << it1->second << it2->second;
// here it1->second=it2->second=3, although I would have expected it2 to be equal to map.end().
}
我可以使用||而不是&amp;&amp;,但我不确定这是正确的方法。我只想拥有运营商&lt;以这样的方式实现,我能够在我的地图中找到对象,而不会出现任何错误,就像我链接到的代码中的情况一样。
感谢。
答案 0 :(得分:7)
是的,这个运算符实现没有多大意义。我建议:
bool operator<(const myStruct& rhs) const {
return rhs.a < this->a || (rhs.a == this->a && rhs.b < this->b);
}
答案 1 :(得分:6)
bool operator<(const myStruct& rhs) const {
if (a < rhs.a) return true;
if (a == rhs.a) return b < rhs.b;
return false;
}
如果您正在寻找对许多数据成员的概括,那么使用C ++ 11 std::tie就是一个很好的例子:
struct S {
int n;
std::string s;
float d;
bool operator<(const S& rhs) const {
return std::tie(n, s, d) < std::tie(rhs.n, rhs.s, rhs.d);
}
};
答案 2 :(得分:5)
问题是您的运营商没有定义strict weak ordering。仔细考虑一下{1,2}
和{2,1}
的示例将如何落入您的运算符中。假设X = {1,2}
和Y = {2,1}
。
X&lt; Y'是1&lt; 2 AND 2&lt; 1?不,因此X不小于Y.
Y&lt; X?是2&lt; 1 AND 1&lt; 2?不,因此Y不小于X.
所以,如果X不小于Y,且Y不小于X,那还剩下什么?他们是平等的。
您需要选择结构中的一个成员,a
或b
作为主要比较。如果主要比较结果相同,那么只有然后才能检查次要比较。就像你alphabetize什么时候一样。首先你检查第一个字母,只有它们相等,你才能继续下一个字母。 Hans Passant提供了一个例子。
这是您的运营商更严重的问题示例。我上面给出的那个不是必然坏,因为也许你想要 {1,2}
被认为等于{2,1}
。基本问题是通过这样的一组值进行裁剪:考虑X = {1,1}, Y = {1,2}, Z = {2,2}
对于你的算子,X最终小于Z,因为1小于2.但X出来等于Y,Y出来等于Z.为了遵守严格的弱排序,如果X = Y ,和Y = Z,那么X应该等于Z.但在这种情况并非如此。
答案 3 :(得分:3)
你问过关于四个int成员的概括,这里是我如何构建这样的代码以获得最大的清晰度。
bool operator<(const myStruct& rhs) const
{
if (a < rhs.a)
return true;
if (a > rhs.a)
return false;
if (b < rhs.b)
return true;
if (b > rhs.b)
return false;
if (c < rhs.c)
return true;
if (c > rhs.c)
return false;
if (d < rhs.d)
return true;
if (d > rhs.d)
return false;
return false;
}
您可以根据需要轻松地为这么多数据成员扩展此类代码。
答案 4 :(得分:1)
最简单的解决方案使用std::tie
来比较元组。
return std::tie(rhs.a, rhs.b) < std::tie(a, b);
这可以非常快速地简化为更多数据成员。
答案 5 :(得分:1)
我更喜欢通过比较相等的元素来写这个,直到找到两个不同的元素:
bool operator<(const myStruct& rhs) const {
if (a != rhs.a)
return a < rhs.a;
if (b != rhs.b)
return b < rhs.b;
return false; // this and rhs are equal.
}
我发现这比使用||的混合编写单个表达式更清晰,更具扩展性和&amp;&amp; (根据@HansPassant),比@jahhaj的每次通过测试的方法更紧凑,导致return true;
或return false;
。性能大致相同,除非您了解值的分布。有一个论点可以避免使用operator==()
而只使用operator<()
,但这只适用于您尝试编写最大通用模板代码的情况。
答案 6 :(得分:0)
问题是你需要知道你的结构代表什么。否则定义&lt;操作员会变得武断。其他人将无法给你一个合适的答案。举个例子,你的结构代表2D中一个点的cartisian坐标。在这种情况下,您可以定义一个有意义的排序运算符,例如距结构原点的距离。
,即距离d1 = this-&gt; a * this-&gt; a + this-&gt; b * this-&gt; b 距离d2 = rhs.a * rhs.a + rhs.b * rhs.b if(d1&lt; d2) 返回true; 其他 返回false;