为什么我必须为每个命名空间定义一个散列函数作为unordered_set



我想为我正在编写的类制作一个哈希函数,我想让这个哈希函数成为该类的朋友,这样我就不必编写不必要的getter方法。为了做到这一点,我在这篇SO帖子中遵循了公认的答案。但我希望能够将对象插入到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);
}

我的问题是:为什么我必须在stdboost命名空间中创建一个散列函数才能使其工作?我想说,我有一个直觉为什么,但我想要一个非常详细的解释。我想要任何替代的解决方案来解决上面代码段中有很多重复代码的问题(但不是像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;
}
};

事实上,在这种情况下,使用return boost::hash_value(v.v);可以使哈希函数更加简单。

这已经足够让Boost的无序容器与您的类型一起工作了:

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

添加std支持

现在这不是问题:

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

现场演示

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

最新更新