为何Entity类内重载的operator()无法作为unordered_map哈希器?
operator()作为哈希函数无法用于默认unordered_map的问题 我在自定义C++结构体Entity中重载了operator()作为哈希函数,同时重载==运算符用于相等判断。但实例化默认哈希器的unordered_map<const Entity, bitset<24>>时编译报错;将哈希逻辑提取至独立的KeyHasher结构体则可正常运行。请问该operator()存在什么问题?
代码示例
#include <bitset> #include <unordered_map> using namespace std; struct Entity { string name; size_t operator()(const Entity& k) const noexcept { return std::hash<string>{}(k.name); } bool operator== (const Entity& e) const noexcept { return e.name == name; } }; struct KeyHasher { size_t operator()(const Entity& k) const noexcept { return std::hash<string>{}(k.name); } }; int main(){ // unordered_map<const Entity, bitset<24>, KeyHasher> m1; // 正常编译 unordered_map<const Entity, bitset<24>> m2; // 编译报错:unordered_map构造函数非法 return 0; }
错误信息
<source>: In function 'int main()': <source>:25:43: error: use of deleted function 'std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map() [with _Key = const Entity; _Tp = std::bitset<24>; _Hash = std::hash<const Entity>; _Pred = std::equal_to<const Entity>; _Alloc = std::allocator<std::pair<const Entity, std::bitset<24> > >]' 25 | unordered_map<const Entity, bitset<24>> m2; | ^~ In file included from /opt/compiler-explorer/gcc-cxx-modules-trunk-20220427/include/c++/11.0.0/unordered_map:47, from <source>:3: /opt/compiler-explorer/gcc-cxx-modules-trunk-20220427/include/c++/11.0.0/bits/unordered_map.h:141:7: note: 'std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map() [with _Key = const Entity; _Tp = std::bitset<24>; _Hash = std::hash<const Entity>; _Pred = std::equal_to<const Entity>; _Alloc = std::allocator<std::pair<const Entity, std::bitset<24> > >]' is implicitly deleted because the default definition would be ill-formed: 141 | unordered_map() = default;
问题原因与解决方法
核心原因
std::unordered_map默认使用的哈希器是std::hash<Key>模板,而非你在Entity内部重载的operator()。你在Entity中重载的operator()只是让Entity本身成为一个函数对象,但这和标准库要求的std::hash特化完全是两回事。
当你声明unordered_map<const Entity, ...>时,编译器会尝试实例化std::hash<const Entity>,但标准库并未为你的自定义类型提供这个特化版本,导致哈希器类型无效,进而使得unordered_map的默认构造函数被隐式删除,最终编译报错。
而使用KeyHasher时,你显式指定了哈希器类型,unordered_map会直接调用KeyHasher的operator()计算哈希,因此可以正常编译。
解决方法
方法1:显式指定哈希器为Entity类型
既然Entity本身是合法的函数对象,你可以直接将它作为unordered_map的哈希器模板参数:
unordered_map<const Entity, bitset<24>, Entity> m2;
方法2:特化std::hash<Entity>
为你的自定义类型特化标准库的std::hash模板,这样unordered_map就能自动识别并使用你的哈希逻辑:
namespace std { template<> struct hash<Entity> { size_t operator()(const Entity& k) const noexcept { return hash<string>{}(k.name); } }; }
添加这段特化代码后,原本的unordered_map<const Entity, bitset<24>> m2;就能正常编译运行。
补充说明
你在Entity内部重载的operator()本身没有语法错误,它可以作为普通函数对象使用,但不符合std::unordered_map默认哈希器的查找规则。默认情况下,unordered_map只会优先使用std::hash<Key>的特化,或者你显式传入的哈希器类型。
内容的提问来源于stack exchange,提问作者ExpertNoob1

