为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C++
慕容3067478 2019-10-09 16:45:01
为了支持用户定义的键类型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.hVC10 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标准?有便携式的方法吗?
查看完整描述

3 回答

?
守候你守候我

TA贡献1802条经验 获得超10个赞

明确允许并鼓励您向名称空间* 添加特殊化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。)


*)我想,只要其中一种涉及类型是用户定义的即可。


查看完整回答
反对 回复 2019-10-09
?
慕侠2389804

TA贡献1719条经验 获得超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

}

当然


hashX可能也是一个全局静态函数

在第二种情况下,您可以通过

老式仿函数对象(struct Xhasher { size_t operator(const X&) const; };)

std::hash<X>()

任何满足签名的绑定表达式-


查看完整回答
反对 回复 2019-10-09
?
繁星淼淼

TA贡献1775条经验 获得超11个赞

涵盖了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。


查看完整回答
反对 回复 2019-10-09
  • 3 回答
  • 0 关注
  • 796 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信