如何将 unordered_set 与自定义结构一起使用?

2022-01-17 00:00:00 set struct c++ c++11 unordered-set

我想将 unordered_set 与自定义 struct 一起使用.就我而言,自定义 struct 表示欧几里得平面中的 2D 点.我知道应该定义一个哈希函数和比较器运算符,我已经这样做了,您可以在下面的代码中看到:

结构点{诠释 X;整数 Y;点():X(0),Y(0){};Point(const int& x, const int& y) : X(x), Y(y) {};点(常量 IPoint& 其他){X = 其他.X;Y = 其他.Y;};点&运算符=(常量点和其他){X = 其他.X;Y = 其他.Y;返回*这个;};bool operator==(const Point& other) {if (X == other.X && Y == other.Y)返回真;返回假;};布尔运算符<(常量点&其他){if (X < other.X )返回真;else if (X == other.X && Y == other.Y)返回真;返回假;};size_t operator()(const Point& pointToHash) const {size_t 哈希 = pointToHash.X + 10 * pointToHash.Y;返回哈希;};};

但是,如果我按如下方式定义集合,则会出现以下错误:

unordered_set我的集;

<块引用>

错误 C2280 'std::hash<_Kty>::hash(const std::hash<_Kty> &)':试图引用已删除的函数

我错过了什么?

解决方案

std::unordered_set 的第二个模板参数是用于散列的类型.并且在您的情况下默认为 std::hash<Point> ,它不存在.所以你可以使用 std::unordered_set<Point,Point> 如果哈希是相同的类型.

或者,如果您不想指定散列器,请为 Point 定义 std::hash 的特化,然后摆脱成员函数并实现散列在您的专业化的 operator() 的主体中,或从 std::hash 专业化调用成员函数.

#include <unordered_set>结构点{诠释 X;整数 Y;点():X(0),Y(0){};Point(const int& x, const int& y) : X(x), Y(y) {};点(常量点和其他){X = 其他.X;Y = 其他.Y;};点&运算符=(常量点和其他){X = 其他.X;Y = 其他.Y;返回*这个;};bool operator==(const Point& other) const {if (X == other.X && Y == other.Y)返回真;返回假;};布尔运算符<(常量点&其他){if (X < other.X )返回真;else if (X == other.X && Y == other.Y)返回真;返回假;};//这可以移入 std::hash<Point>::operator()size_t operator()(const Point& pointToHash) const noexcept {size_t 哈希 = pointToHash.X + 10 * pointToHash.Y;返回哈希;};};命名空间标准{模板<>结构哈希<点>{std::size_t operator()(const Point& p) const noexcept{返回 p(p);}};}主函数(){//如果 std::hash<Point> 不需要指定哈希存在std::unordered_set<Point>p;返回0;}

演示

I want to use an unordered_set with a custom struct. In my case, the custom struct represents a 2D point in an euclidean plane. I know that one should define a hash function and comparator operator and I have done so as you can see in my code below:

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;
    };
};

However, I'm getting the error below, if I define the set as follows:

unordered_set<Point> mySet;

Error C2280 'std::hash<_Kty>::hash(const std::hash<_Kty> &)': attempting to reference a deleted function

What am I missing?

解决方案

The second template parameter to std::unordered_set is the type to use for hashing. and will default to std::hash<Point> in your case, which doesn't exist. So you can use std::unordered_set<Point,Point> if the hasher is the same type.

Alternatively if you do not want to specify the hasher, define a specialization of std::hash for Point and either get rid of the member function and implement the hashing in the body of your specialization's operator(), or call the member function from the std::hash specialization.

#include <unordered_set>

struct Point {
    int X;
    int Y;

    Point() : X(0), Y(0) {};
    Point(const int& x, const int& y) : X(x), Y(y) {};
    Point(const Point& 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) const {
        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;
    };

    // this could be moved in to std::hash<Point>::operator()
    size_t operator()(const Point& pointToHash) const noexcept {
        size_t hash = pointToHash.X + 10 * pointToHash.Y;
        return hash;
    };

};

namespace std {
    template<> struct hash<Point>
    {
        std::size_t operator()(const Point& p) const noexcept
        {
            return p(p);
        }
    };
}


int main()
{
    // no need to specify the hasher if std::hash<Point> exists
    std::unordered_set<Point> p;
    return 0;
}

Demo

相关文章