为何std::set<array<int,N>>可用而std::unordered_set<array<int,N>>不可用?兼谈map类差异
核心原因在于两类容器的底层实现依赖的机制完全不同:
一、std::set/std::map能正常工作的原因
std::set和std::map是有序关联容器,底层基于红黑树实现,它们只需要容器内的元素支持比较操作(默认用std::less<T>,对应operator<)就能正常工作。
C++标准已经为std::array<T,N>重载了operator<(以及其他比较运算符),采用字典序进行比较——比如两个std::array<int,2>,先比较第一个元素,相等再比较第二个,以此类推。所以std::set<std::array<int,N>>可以直接使用,红黑树能通过比较操作完成元素的排序和插入、查找逻辑。
二、std::unordered_set/std::unordered_map无法直接使用的原因
std::unordered_set和std::unordered_map是哈希关联容器,底层基于哈希表实现,它们需要元素满足两个条件:
- 支持相等判断(默认用
std::equal_to<T>,对应operator==); - 有对应的哈希函数(即
std::hash<T>的特化版本)。
对于std::array<T,N>来说,第一个条件是满足的——标准库已经重载了operator==,可以逐元素比较是否相等。但问题在于:C++标准库没有为std::array<T,N>提供std::hash的特化版本,编译器找不到对应的哈希函数来计算std::array对象的哈希值,因此会编译报错。
解决方法:自定义哈希函数
要让std::unordered_set<std::array<int,N>>或std::unordered_map<std::array<int,N>, V>正常工作,你需要手动提供一个哈希函数。比如可以写一个模板类,遍历std::array的每个元素并组合哈希值:
#include <array> #include <unordered_set> #include <functional> template <typename T, size_t N> struct ArrayHash { size_t operator()(const std::array<T, N>& arr) const { size_t hash_val = 0; for (const auto& elem : arr) { // 用std::hash<T>计算单个元素的哈希,再组合 hash_val ^= std::hash<T>()(elem) + 0x9e3779b9 + (hash_val << 6) + (hash_val >> 2); } return hash_val; } }; // 使用方式 std::unordered_set<std::array<int, 3>, ArrayHash<int, 3>> my_set;
这样就能让哈希容器正常处理std::array类型的元素了。
内容的提问来源于stack exchange,提问作者abcdefasf

