我正在使用带有struct
的STL地图作为密钥。这是地图的定义:
std::map<Coord2<uint8_t>, MapTile> tile_;
struct
:
template <typename T>
struct Coord2
{
T x;
T y;
bool operator<(const Coord2<T> &coord) const { return (x < coord.x || y < coord.y); }
bool operator>(const Coord2<T> &coord) const { return (x > coord.x || y > coord.y); }
}
我会因为比较而遇到地图问题吗?
答案 0 :(得分:14)
此operator<
不适合与C ++标准库的关联容器一起使用。
比较器必须提供strict weak ordering,而你不提供。请考虑以下操作数来证明其不一致性:
a = { x = 1, y = 0 }
b = { x = 0, y = 1 }
根据这些输入a < b == true
和b < a == true
,b != a
。
此类型的正确比较可能是:
if (x < coord.x)
return true;
if (coord.x < x)
return false;
return y < coord.y;
(当然可以以更紧凑的方式编写这个正确的代码,但是我已经调试了错误实现的严格弱顺序导致的足够错误,我强烈建议在比较中非常明确,这样很明显这是正确的。通过这个实现,很明显,如果y
值比较相等,我们只比较x
值,这就是我们想要的。)
答案 1 :(得分:13)
对于两个值,James的答案是理想的,对于更多的成员来说它变得复杂,因此在多个值上实现严格的弱排序的简单方法是创建这些值的元组并比较元组:
return boost::tie(x, y, z) < boost::tie(coord.x, coord.y, coord.z);
您需要做的就是让每个成员都为LessThanComparable,然后#include <boost/tuple/tuple_comparison.hpp>
并在每个tie
表达式中以相同的顺序列出成员。
在C ++ 11中,您可以#include <tuple>
使用std::tie
代替。
元组的比较定义为进行词典比较,因此比较第一个元素,如果结果为真,则比较完成并返回true,否则下一个元素将以相同的方式进行比较,对于每对元素元素。只要每个元素类型都有正确定义的operator<
,这就可以确保正确的严格弱排序。
答案 2 :(得分:2)
首先注意:您不需要operator>
,因为std::map
无论如何都只会使用operator<
。
但是,operator<
不适合std::map
键,因为它没有定义严格的弱排序。实际上,它甚至没有实现严格的部分排序,因为它违反了传递性和反对称性:考虑以下定义:
coord p = { 2, 2 };
coord q = { 0, 4 };
coord r = { 1, 1 };
也不p < q
返回true
因为2 < 4
,q < r
返回true
因为0 < 1
,但p < r
返回false
}}。因此违反了传递性。
此外,p < q
不仅返回true,q < p
也是如此,因为0 < 2
。换句话说,根据您的运营商,p
和q
中的每一个都会被视为小于另一个。