如何解决unordered_map中整数对的哈希函数错误?

问题描述 投票:0回答:2

我有以下带有

unordered_map
成员的类,以及为
pair<int,int>

定义的哈希函数
class abc
{
public:
    unordered_map<pair<int,int>, int> rules;
    unsigned nodes;
    unsigned packet;     
};

namespace std {
template <>
class hash<std::pair<int, int>>
{
public:
    size_t operator()(const pair<int, int> &x) const
    {
        size_t h = std::hash<int>()(x.first) ^ std::hash<int>()(x.second);
        return  h ;
    }
};
}

但是我收到以下错误:

error: invalid use of incomplete type ‘struct std::hash<std::pair<int, int> >
    
error: declaration of ‘struct std::hash<std::pair<int, int> >
    
error: type ‘std::__detail::_Hashtable_ebo_helper<1, std::hash<std::pair<int, int> >, true>’ is not a direct base of ‘std::__detail::_Hash_code_base<std::pair<int, int>, std::pair<const std::pair<int, int>, int>, std::__detail::_Select1st, std::hash<std::pair<int, int> >, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, true>’
c++ c++11 hash stl unordered-map
2个回答
63
投票

不幸的是,这个程序有未定义的行为。 C++11 §17.6.4.2.1:

仅当声明依赖于用户定义类型并且专门化满足原始模板的标准库要求且未明确禁止时,程序才可以将任何标准库模板的模板专门化添加到命名空间 std。

hash<pair<int,int>>
仅取决于原始库类型和标准库类型。通过在命名空间
std
之外定义哈希类,并在映射声明中显式使用该哈希,可以轻松解决此问题:

struct pairhash {
public:
  template <typename T, typename U>
  std::size_t operator()(const std::pair<T, U> &x) const
  {
    return std::hash<T>()(x.first) ^ std::hash<U>()(x.second);
  }
};

class abc {
  std::unordered_map<std::pair<int,int>, int, pairhash> rules;
};

编辑:我在这里使用 xor 来组合成对成员的哈希值,因为我很懒,但对于认真使用来说 xor 是一个相当蹩脚的哈希组合函数


4
投票

我更喜欢依赖

std::hash<uintmax_t>
的标准实现来混合
std::pair
的组件的哈希值:

#include <functional>
#include <utility>

struct hash_pair final {
    template<class TFirst, class TSecond>
    size_t operator()(const std::pair<TFirst, TSecond>& p) const noexcept {
        uintmax_t hash = std::hash<TFirst>{}(p.first);
        hash <<= sizeof(uintmax_t) * 4;
        hash ^= std::hash<TSecond>{}(p.second);
        return std::hash<uintmax_t>{}(hash);
    }
};
© www.soinside.com 2019 - 2024. All rights reserved.