使用pair<int,int>作为unordered_map键是否需自定义哈希函数?
不能直接用
std::pair<int,int>作为std::unordered_map的键(C++11及以上版本) 不行,哪怕编译器和标准库支持C11及更高版本,默认情况下也不能直接将std::pair<int, int>作为std::unordered_map的键。原因很明确:C标准库从未为std::pair模板提供过std::hash的特化版本,而std::unordered_map作为无序容器,要求键类型必须有对应的哈希函数(要么是默认的std::hash<Key>,要么是用户指定的自定义哈希器)。
你遇到的编译错误,正是因为标准库的静态断言检查发现找不到符合要求的哈希函数,直接触发了报错。
至于ChatGPT说这段代码可以运行,是它混淆了std::map和std::unordered_map的要求:std::map是有序容器,只需要键类型支持operator<(std::pair默认提供了这个运算符);但std::unordered_map必须同时满足两个条件:
- 键类型支持
operator==(std::pair默认满足) - 有对应的哈希函数(
std::pair默认没有)
解决方案:自定义哈希函数
要让std::pair<int,int>作为std::unordered_map的键,你需要提供一个自定义哈希器,以下是两种常见实现方式:
方式1:定义自定义哈希结构体,声明时指定
#include <iostream> #include <unordered_map> #include <utility> #include <functional> // 自定义哈希结构体,采用boost风格的hash_combine实现,哈希分布更均匀 struct PairHash { template <typename T1, typename T2> std::size_t operator()(const std::pair<T1, T2>& p) const { std::size_t seed = 0; std::hash<T1> hasher1; std::hash<T2> hasher2; // 组合哈希值,避免简单异或导致的分布不均 seed ^= hasher1(p.first) + 0x9e3779b9 + (seed << 6) + (seed >> 2); seed ^= hasher2(p.second) + 0x9e3779b9 + (seed << 6) + (seed >> 2); return seed; } }; int main() { // 声明unordered_map时,指定第三个模板参数为自定义哈希结构体 std::unordered_map<std::pair<int, int>, int, PairHash> myMap; myMap[{1, 2}] = 10; myMap[{3, 4}] = 20; int value1 = myMap[{1, 2}]; int value2 = myMap[{3, 4}]; std::cout << value1 << " " << value2 << std::endl; return 0; }
方式2:特化std::hash<std::pair<int,int>>(不推荐但可行)
你可以在std命名空间下特化std::hash,不过C++标准不鼓励对标准库模板进行非标准特化,仅在特定场景下使用:
#include <iostream> #include <unordered_map> #include <utility> #include <functional> namespace std { template<> struct hash<std::pair<int, int>> { size_t operator()(const std::pair<int, int>& p) const { size_t seed = 0; hash<int> hasher; seed ^= hasher(p.first) + 0x9e3779b9 + (seed << 6) + (seed >> 2); seed ^= hasher(p.second) + 0x9e3779b9 + (seed << 6) + (seed >> 2); return seed; } }; } int main() { // 此时可直接使用,无需额外指定哈希器 std::unordered_map<std::pair<int, int>, int> myMap; myMap[{1, 2}] = 10; myMap[{3, 4}] = 20; int value1 = myMap[{1, 2}]; int value2 = myMap[{3, 4}]; std::cout << value1 << " " << value2 << std::endl; return 0; }
关键注意点
- 哈希函数的核心是生成均匀分布的哈希值,避免碰撞,上面的
hash_combine方式比简单的异或/加减更稳健 - 从C11到最新的C23,标准库都没有为
std::pair提供默认哈希,所以不管哪个版本都需要自定义哈希函数才能使用unordered_map
内容的提问来源于stack exchange,提问作者Baylor
相关产品推荐
相关产品推荐

