如何在无序容器中将std :: hash <Key> :: operator()专用于用户定义类型?

为了支持用户定义的键类型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> 使用type 的默认哈希值编写将更方便X,例如与编译器和库一起提供的类型。经过咨询


C ++标准草案N3242§20.8.12 [unord.hash]和§17.6.3.4[hash.requirements],

增强无序

g ++ include\c++\4.7.0\bits\functional_hash.h

VC10 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标准?


有便携式的方法吗?


慕容3067478
浏览 797回答 3
3回答

守候你守候我

明确允许并鼓励您向名称空间* 添加特殊化std。添加哈希函数的正确方法(基本上是唯一方法)是:namespace std {&nbsp; template <> struct hash<Foo>&nbsp; {&nbsp; &nbsp; size_t operator()(const Foo & x) const&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; /* your code here, e.g. "return hash<int>()(x.value);" */&nbsp; &nbsp; }&nbsp; };}(您可能考虑支持其他受欢迎的专业有std::less,std::equal_to和std::swap。)*)我想,只要其中一种涉及类型是用户定义的即可。

慕侠2389804

我的赌注将放在unordered_map / unorder_set / ...类的Hash模板参数上:#include <unordered_set>#include <functional>struct X&nbsp;{&nbsp; &nbsp; int x, y;&nbsp; &nbsp; 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(){&nbsp; &nbsp; auto hashX = [](const X&x) { return x.gethash(); };&nbsp; &nbsp; Xunset&nbsp; my_set (0, hashX);&nbsp; &nbsp; Xunset2 my_set2(0, hashX); // if you prefer a more flexible set typedef}当然hashX可能也是一个全局静态函数在第二种情况下,您可以通过老式仿函数对象(struct Xhasher { size_t operator(const X&) const; };)std::hash<X>()任何满足签名的绑定表达式-

繁星淼淼

涵盖了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)的类型的表达式Key,则h(k)是类型为的有效表达式size_t。如果h是类型H或的表达式const H,并且u是类型的左值Key,则h(u)是一个有效的表达式,其类型size_t不会修改u。
打开App,查看更多内容
随时随地看视频慕课网APP