使用enum作为unordered_map的pair键时自定义hash遇类型转换错误
问题:枚举类作为pair键时unordered_map哈希实现报错
我想将std::pair作为std::unordered_map的键,但标准库默认未提供该类型的哈希实现,因此参考boost的hash API自行实现了一套,却遇到编译错误。
实例化map的代码如下:
using pair = std::pair<Values, std::string>; std::unordered_map<pair, int, custom_hash<pair>> mp;
使用方式:
void Foo(Values firstKey, std::string secKey, int value) { mp.insert({{firstKey, secKey}, value}); }
由于Values是枚举类,编译时报错:
could not convert 'val' from 'Values' to 'std::__hash_enum<Values, true>'.
这是否意味着模板参数T不能是枚举类型?
完整示例代码:
template <class T> std::size_t hash_value(T val) { return std::hash<T>(val); } template <class T> inline void hash_combine( std::size_t& seed, T const& v) { custom_hash<T>()(v); } template <class A, class B> std::size_t hash_value(std::pair<A, B> const& v) { std::size_t seed = 0; hash_combine(seed, v.first); hash_combine(seed, v.second); return seed; } template <class T> struct custom_hash { typedef T argument_type; typedef std::size_t result_type; std::size_t operator()(T const& val) const { return hash_value(val); } }; enum class Values { one }; using pair = std::pair<Values, std::string>; std::unordered_map<pair, int, custom_hash<pair>> mp; void Foo(Values firstKey, std::string secKey, int value) { mp.insert({{firstKey, secKey}, value}); }
问题分析与修复
错误并非因为模板参数不能是枚举类型,而是你的哈希实现存在两处关键问题:
hash_value函数调用错误:std::hash<T>是类模板,你需要先创建实例再调用其operator()。原代码中std::hash<T>(val)试图将val转换为std::hash<T>类型,这是完全错误的,也是编译报错的直接原因。hash_combine未执行哈希合并:原函数仅调用了哈希计算,但未将结果与传入的seed进行组合,导致所有pair的哈希值始终为0,完全失去哈希的意义。
修复后的代码
#include <functional> #include <string> #include <unordered_map> #include <utility> template <class T> std::size_t hash_value(T const& val) { // 正确调用std::hash的operator() return std::hash<T>{}(val); } template <class T> inline void hash_combine(std::size_t& seed, T const& v) { // 使用boost推荐的哈希组合算法,将新哈希值合并到seed中 seed ^= hash_value(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); } template <class A, class B> std::size_t hash_value(std::pair<A, B> const& v) { std::size_t seed = 0; hash_combine(seed, v.first); hash_combine(seed, v.second); return seed; } template <class T> struct custom_hash { using argument_type = T; using result_type = std::size_t; std::size_t operator()(T const& val) const { return hash_value(val); } }; enum class Values { one }; using pair = std::pair<Values, std::string>; std::unordered_map<pair, int, custom_hash<pair>> mp; void Foo(Values firstKey, std::string secKey, int value) { mp.insert({{firstKey, secKey}, value}); }
补充说明
C++11及以上标准中,std::hash已经原生支持枚举类型(包括强类型枚举enum class),因此无需额外为Values编写特化的哈希函数,只要正确调用std::hash即可。
内容的提问来源于stack exchange,提问作者xyf
相关产品推荐
相关产品推荐

