c++ - 为什么我必须为每个 namespace 定义一个哈希函数作为 unordered_set?

标签 c++ boost hash namespaces

我想为我正在编写的类创建一个哈希函数,并且我想让该哈希函数成为该类的友元,这样我就不必编写不必要的 getter 方法。为此,我遵循 this SO post 中接受的答案。 。但我希望能够将对象插入 std::unordered_setboost::unordered_set 。所以我这样写:

#include <iostream>
#include <unordered_set>
#include <boost/functional/hash.hpp>
#include <boost/unordered_set.hpp>

class Vec;
namespace std { // line [c]
    template<>
    struct hash<Vec> {
    public:
        size_t operator()(const Vec &v) const;
    };
}

class Vec {
private:
    std::vector<int> v;
public:
    friend size_t std::hash<Vec>::operator ()(const Vec& v) const; // line [d]
    friend bool operator == (const Vec& lhs, const Vec& rhs) { return lhs.v == rhs.v; }
};

namespace std { // line [e]
    size_t hash<Vec>::operator()(const Vec &v) const {
        return boost::hash<std::vector<int> >()(v.v);
    }
}

int main() {
    Vec v;
    std::unordered_set<Vec> s1; // line [f]
    s1.insert(v); // line [g]
    boost::unordered_set<Vec> s2; // line [a]
    s2.insert(v); // line [b]
}

但是我发现在尝试编译它时出现了一长串错误。然后当我删除行 [a,b] 时,它按预期编译并运行。然后,不要删除行 [a,b] ,我 (1) 将它们留在里面,(2) 删除了行 [f,g]和 (3) 更改了行 [c,d,e]boost而不是std ,代码再次可以正确编译。最后,我尝试在 boost 中重复声明哈希结构。命名空间:

#include <iostream>
#include <unordered_set>
#include <boost/functional/hash.hpp>
#include <boost/unordered_set.hpp>

class Vec;
namespace std {
    template<>
    struct hash<Vec> {
    public:
        size_t operator()(const Vec &v) const;
    };
}
// new: {
namespace boost {
    template<>
    struct hash<Vec> {
    public:
        size_t operator()(const Vec &v) const;
    };
}
// }

class Vec {
private:
    std::vector<int> v;
public:
    friend size_t std::hash<Vec>::operator ()(const Vec& v) const;
    // new: {
    friend size_t boost::hash<Vec>::operator ()(const Vec& v) const;
    // }
    friend bool operator == (const Vec& lhs, const Vec& rhs) { return lhs.v == rhs.v; }
};

namespace std {
    size_t hash<Vec>::operator()(const Vec &v) const {
        return boost::hash<std::vector<int> >()(v.v);
    }
}
// new: {
namespace boost {
    size_t hash<Vec>::operator()(const Vec &v) const {
        return boost::hash<std::vector<int> >()(v.v);
    }
}
// }

int main() {
    Vec v;
    std::unordered_set<Vec> s1;
    s1.insert(v);
    boost::unordered_set<Vec> s2;
    s2.insert(v);
}

我的问题是:为什么我必须在 std 中创建哈希函数和boost命名空间让它工作?我想说我有一个直觉,但我想要一个非常详细的解释。我想要任何替代解决方案来解决上述代码段中存在大量重复代码的事实(但不是类似 boost::unordered_set<Vec, my_vec_class_hash> 因为我希望它是“自动”的)。

最佳答案

通过使用 Boost 的支持 ADL 的自定义点 hash_value,您可以大大减少困惑:

class Vec {
  private:
    std::vector<int> v;

    friend size_t hash_value(const Vec& v) {
        return boost::hash_range(begin(v.v), end(v.v));
    }
    friend bool operator==(const Vec& lhs, const Vec& rhs) {
        return lhs.v == rhs.v;
    }
};

In fact, the hash function can be even simpler with return boost::hash_value(v.v); in this case.

这已经足以使 Boost 的无序容器适用于您的类型:

boost::unordered_set<Vec> s2;
s2.insert(v);

添加标准支持

现在这不是问题了:

template <> struct std::hash<Vec> : boost::hash<Vec> {};

现场演示

<强> Live On Coliru

#include <boost/functional/hash.hpp>
#include <boost/unordered_set.hpp>
#include <iostream>
#include <unordered_set>

class Vec {
  private:
    std::vector<int> v;

    friend size_t hash_value(const Vec& v) {
        return boost::hash_value(v.v);
        //return boost::hash_range(begin(v.v), end(v.v));
    }
    friend bool operator==(const Vec& lhs, const Vec& rhs) {
        return lhs.v == rhs.v;
    }
};

template <> struct std::hash<Vec> : boost::hash<Vec> {};

int main() {
    Vec v;
    std::unordered_set<Vec> s1;
    s1.insert(v);
    boost::unordered_set<Vec> s2;
    s2.insert(v);
}

关于c++ - 为什么我必须为每个 namespace 定义一个哈希函数作为 unordered_set?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67202331/

相关文章:

c++ - 编译器去虚拟化,是不是太聪明了?

c++ - 绑定(bind)并连接的 Boost.Asio 数据报 (UDP) 套接字

c++ - 完全删除 std::map<int, string> 的内存

c++ - “use algorithms; don’ t 为多步逻辑编写代码?

macos - Dylibs 和 OS X

c++ - 如何组合两个 Boost Geometry 变压器?

node.js - Express.js 如何在登录时和之后使用安全性

c++ - 为什么我的构造函数不会在循环执行时重新初始化变量?

linux - 为什么 Doxygen 会创建这么多空文件夹?

ruby - XML 到哈希转换 : Nori drops the attributes of the deepest XML elements