在std::unordered_set<Key>
和std::unordered_map<Key, Value>
中支持用户定义的密钥类型
一个人必须提供operator==(Key, Key)
和一个哈希函子:
struct X { int id; /* ... */ };
bool operator==(X a, X b) { return a.id == b.id; }
struct MyHash {
size_t operator()(const X& x) const { return std::hash<int>()(x.id); }
};
std::unordered_set<X, MyHash> s;
仅编写std::unordered_set<X>
会更方便
使用类型X
的默认哈希,
喜欢与编译器和库一起出现的类型。
咨询后
include\c++\4.7.0\bits\functional_hash.h
include\xfunctional
似乎可以专门化std::hash<X>::operator()
:
namespace std { // argh!
template <>
inline size_t
hash<X>::operator()(const X& x) const { return hash<int>()(x.id); } // works for MS VC10, but not for g++
// or
// hash<X>::operator()(X x) const { return hash<int>()(x.id); } // works for g++ 4.7, but not for VC10
}
鉴于编译器对C ++ 11的支持尚未实验 - 我没有尝试过Clang ---,这些是我的问题:
将这样的专业化添加到命名空间std
是否合法?我对此感到复杂。
哪个std::hash<X>::operator()
版本(如果有)符合C ++ 11标准?
有可行的方法吗?
答案 0 :(得分:115)
明确允许并鼓励您将特化添加到命名空间std
*。添加哈希函数的正确(并且基本上是唯一的)方式是:
namespace std {
template <> struct hash<Foo>
{
size_t operator()(const Foo & x) const
{
/* your code here, e.g. "return hash<int>()(x.value);" */
}
};
}
(您可能考虑支持的其他热门专业有std::less
,std::equal_to
和std::swap
。)
*)只要其中一个涉及的类型是用户定义的,我猜想。
答案 1 :(得分:6)
我打赌将在unordered_map / unorder_set / ...类的Hash模板参数上:
#include <unordered_set>
#include <functional>
struct X
{
int x, y;
std::size_t gethash() const { return (x*39)^y; }
};
typedef std::unordered_set<X, std::size_t(*)(const X&)> Xunset;
typedef std::unordered_set<X, std::function<std::size_t(const X&)> > Xunset2;
int main()
{
auto hashX = [](const X&x) { return x.gethash(); };
Xunset my_set (0, hashX);
Xunset2 my_set2(0, hashX); // if you prefer a more flexible set typedef
}
当然
struct Xhasher { size_t operator(const X&) const; };
)std::hash<X>()
答案 2 :(得分:4)
@Kerrek SB已经涵盖1)和3)。
2)尽管g ++和VC10使用不同的签名声明std::hash<T>::operator()
,但两个库实现都符合标准。
标准未指定std::hash<T>
的成员。它只是说每个这样的专业化必须满足std::unordered_set
的第二个模板参数所需的相同“哈希”要求,依此类推。即:
H
是一个函数对象,至少有一个参数类型Key
。H
是可复制的。H
可以破坏。h
是H
或const H
类型的表达式,k
是可转换为(可能const
){{{ 1}},然后Key
是类型为h(k)
的有效表达式。size_t
是h
或H
类型的表达式,而const H
是u
类型的左值,那么Key
是类型为h(u)
的有效表达式,不会修改size_t
。