我一直想将unordered_set与自定义结构一起使用,在我的例子中,自定义结构表示欧几里得平面中的2D点。 现在,我知道应该定义一个哈希函数和比较器运算符,见下文:
struct Point {
int X;
int Y;
Point() : X(0), Y(0) {};
Point(const int& x, const int& y) : X(x), Y(y) {};
Point(const IPoint& other){
X = other.X;
Y = other.Y;
};
Point& operator=(const Point& other) {
X = other.X;
Y = other.Y;
return *this;
};
bool operator==(const Point& other) {
if (X == other.X && Y == other.Y)
return true;
return false;
};
bool operator<(const Point& other) {
if (X < other.X )
return true;
else if (X == other.X && Y == other.Y)
return true;
return false;
};
size_t operator()(const Point& pointToHash) const {
size_t hash = pointToHash.X + 10 * pointToHash.Y;
return hash;
};
};
即使我只是定义了设置,我也会收到以下错误。
unordered_set<Point> mySet;
错误C2280'std :: hash&lt; _Kty&gt; :: hash(const std :: hash&lt; _Kty&gt;&amp;)': 试图引用已删除的功能
在这里显然遗漏了什么但是????
答案 0 :(得分:4)
std :: unordered_set的第二个模板参数是用于散列的类型。并且在您的情况下默认为std::hash<Point>
,这不存在。因此,如果hasher是相同的类型,则可以使用std::unordered_set<Point,Point>
。
或者,如果您不想指定hasher,请为std::hash
定义Point
的特化,然后摆脱成员函数并在专业化的{{1}中实现散列或者从std :: hash specialization调用成员函数。
operator()
答案 1 :(得分:2)
尽管上述解决方案可让您编译代码,但请避免使用散列函数作为点。由b
参数化的一维子空间,其在行y = -x/10 + b
上的所有点将具有相同的哈希值。最好使用64位哈希,例如,高32位是x坐标,低32位是y坐标(例如)。看起来像
uint64_t hash(Point const & p) const noexcept
{
return ((uint64_t)p.X)<<32 | (uint64_t)p.Y;
}
答案 2 :(得分:0)
我想通过提供更多提示来扩展rmawatson's answer:
struct
,您不需要定义operator=
或Point(const Point& other)
,因为(重新)实现了默认行为。您可以通过删除operator==
子句来简化if
,如下所示:
bool operator==(const Point& other) { return X == other.X && Y == other.Y; };
您的operator<
中有一个错误:在else if
子句中,如果两点相等,则返回true
。这违反了strict weak ordering的要求。因此,我建议改用以下代码:
bool operator<(const Point& other) { return X < other.X || (X == other.X && Y < other.Y); };
此外,自C++11起,您可以使用lambda expressions而不是定义哈希和比较函数。这样,如果您不需要struct
,则无需指定任何运算符。将所有内容放在一起,您的代码可以编写如下:
struct Point {
int X, Y;
Point() : X(0), Y(0) {};
Point(const int x, const int y) : X(x), Y(y) {};
};
int main() {
auto hash = [](const Point& p) { return p.X + 10 * p.Y; };
auto equal = [](const Point& p1, const Point& p2) { return p1.X == p2.X && p1.Y == p2.Y; };
std::unordered_set<Point, decltype(hash), decltype(equal)> mySet(8, hash, equal);
return 0;
}
但是,正如CJ13's answer中所述,您的哈希函数可能不是最好的。 handcraft a hash function的另一种方法如下:
auto hash = [](const Point& p) { return std::hash<int>()(p.X) * 31 + std::hash<int>()(p.Y); };
可以找到更通用的哈希解决方案的想法here。