std::hash
| 定义于头文件 <bitset>
|
||
| 定义于头文件 <coroutine>
|
||
| 定义于头文件 <chrono>
|
(C++26 起) |
|
| 定义于头文件 <filesystem>
|
||
| 定义于头文件 <functional>
|
||
| 定义于头文件 <memory>
|
||
| 定义于头文件 <optional>
|
||
| 定义于头文件 <stacktrace>
|
||
| 定义于头文件 <string>
|
||
| 定义于头文件 <string_view>
|
||
| 定义于头文件 <system_error>
|
||
| 定义于头文件 <text_encoding>
|
||
| 定义于头文件 <thread>
|
||
| 定义于头文件 <typeindex>
|
||
| 定义于头文件 <variant>
|
||
| 定义于头文件 <vector>
|
||
template< class Key >
struct hash;
|
(C++11 起) | |
无序关联容器 std::unordered_set、std::unordered_multiset、std::unordered_map、std::unordered_multimap 使用模板 std::hash 的特化作为默认哈希函数。
对于给定类型 Key,每个特化 std::hash<Key> 要么是启用的,要么是禁用 的:
- 如果
std::hash<Key>未由程序或用户提供,则它是禁用的。 - 否则,
std::hash<Key>在满足以下所有条件时启用:
- 满足以下所有要求:
- Hash(以
Key作为函数调用参数类型) - DefaultConstructible
- CopyAssignable
- Swappable
- Hash(以
- 给定以下值:
h,类型为std::hash<Key>的对象。k1和k2,类型为Key的对象。
- 满足以下所有要求:
- 如果
k1 == k2是true,那么h(k1) == h(k2)也是true。 - 除非
std::hash<Key>是一个程序定义的特化,否则h(k1)不会抛出异常。
- 如果
- 否则,
std::hash<Key>是禁用的。
禁用的特化不满足 Hash,不满足 FunctionObject,并且以下值均为 false:
std::is_default_constructible<std::hash<Key>>::valuestd::is_copy_constructible<std::hash<Key>>::valuestd::is_move_constructible<std::hash<Key>>::valuestd::is_copy_assignable<std::hash<Key>>::valuestd::is_move_assignable<std::hash<Key>>::value
换句话说,它们存在,但不能被使用。
嵌套类型
|
(C++20 前) |
成员函数
|
构造哈希函数对象
(公开成员函数) |
|
|
计算参数的哈希值
(公开成员函数) |
标准库特化
每个声明
std::hash
模板的头文件同时为以下类型提供已启用的
std::hash
特化:
- 所有无 cv 限定符的 算术类型
- 所有无 cv 限定符的 枚举类型
- 所有无 cv 限定符的 指针类型
- std::nullptr_t
|
一个 独立实现 必须提供上述特化以及默认禁用的特化。 |
(since C++20) |
除此之外,某些头文件还为库类型提供了其他启用的
std::hash
特化(参见
下方
)。
|
对于标准库提供的所有
|
(since C++17) |
标准库类型的特化
语言支持库 |
|
|
std::coroutine_handle
的哈希支持
(类模板特化) |
|
诊断库 |
|
|
(C++11)
|
std::error_code
的哈希支持
(类模板特化) |
|
(C++17)
|
std::error_condition
的哈希支持
(类模板特化) |
|
(C++11)
|
std::type_index
的哈希支持
(类模板特化) |
|
std::stacktrace_entry
的哈希支持
(类模板特化) |
|
|
std::basic_stacktrace
的哈希支持
(类模板特化) |
|
内存管理库 |
|
|
(C++11)
|
std::unique_ptr
的哈希支持
(类模板特化) |
|
(C++11)
|
std::shared_ptr
的哈希支持
(类模板特化) |
|
(C++26)
|
std::indirect
的哈希支持
(类模板特化) |
通用工具库 |
|
|
(C++17)
|
std::optional
的哈希支持
(类模板特化) |
|
(C++17)
|
std::variant
的哈希支持
(类模板特化) |
|
(C++17)
|
std::monostate
的哈希支持
(类模板特化) |
|
(C++11)
|
std::bitset
的哈希支持
(类模板特化) |
容器库 |
|
|
(C++11)
|
std::vector<bool>
的哈希支持
(类模板特化) |
字符串库 |
|
|
(C++11)
|
字符串的哈希支持
(类模板特化) |
文本处理库 | |
| 对 std::text_encoding 的哈希支持(类模板特化) | |
时间库 |
|
|
std::chrono::duration
的哈希支持
(类模板特化) |
|
|
std::chrono::time_point
的哈希支持
(类模板特化) |
|
|
(C++26)
|
std::chrono::day
的哈希支持
(类模板特化) |
|
(C++26)
|
std::chrono::month
的哈希支持
(类模板特化) |
|
(C++26)
|
std::chrono::year
的哈希支持
(类模板特化) |
|
(C++26)
|
std::chrono::weekday
的哈希支持
(类模板特化) |
|
std::chrono::weekday_indexed
的哈希支持
(类模板特化) |
|
|
std::chrono::weekday_last
的哈希支持
(类模板特化) |
|
|
std::chrono::month_day
的哈希支持
(类模板特化) |
|
|
std::chrono::month_day_last
的哈希支持
(类模板特化) |
|
|
std::chrono::month_weekday
的哈希支持
(类模板特化) |
|
|
std::chrono::month_weekday_last
的哈希支持
(类模板特化) |
|
|
std::chrono::year_month
的哈希支持
(类模板特化) |
|
|
std::chrono::year_month_day
的哈希支持
(类模板特化) |
|
|
std::chrono::year_month_day_last
的哈希支持
(类模板特化) |
|
|
std::chrono::year_month_weekday
的哈希支持
(类模板特化) |
|
|
std::chrono::year_month_weekday_last
的哈希支持
(类模板特化) |
|
|
std::chrono::zoned_time
的哈希支持
(类模板特化) |
|
|
std::chrono::leap_second
的哈希支持
(类模板特化) |
|
输入/输出库 |
|
|
std::filesystem::path
的哈希支持
(类模板特化) |
|
并发支持库 |
|
|
(C++11)
|
std::thread::id
的哈希支持
(类模板特化) |
注释
实际的哈希函数取决于具体实现,除上述规定要求外无需满足其他质量标准。值得注意的是,某些实现使用将整数映射自身的简易(恒等)哈希函数。换言之,这些哈希函数的设计用途是配合无序关联容器工作,而非作为加密哈希等场景使用。
哈希函数仅需保证在同一程序执行过程中对相同输入产生相同结果;这允许使用加盐哈希来防范碰撞拒绝服务攻击。
没有针对C字符串的特化。 std :: hash < const char * > 生成的是指针值(内存地址)的哈希,不会检查字符数组的内容。
针对
std::pair
和标准容器类型的额外特化版本,以及用于组合哈希的实用函数,可在
boost::hash
中获得。
示例
#include <cstddef> #include <functional> #include <iomanip> #include <iostream> #include <string> #include <unordered_set> struct S { std::string first_name; std::string last_name; bool operator==(const S&) const = default; // 自 C++20 起 }; // C++20 之前。 // bool operator==(const S& lhs, const S& rhs) // { // return lhs.first_name == rhs.first_name && lhs.last_name == rhs.last_name; // } // 自定义哈希可以是独立的函数对象。 struct MyHash { std::size_t operator()(const S& s) const noexcept { std::size_t h1 = std::hash<std::string>{}(s.first_name); std::size_t h2 = std::hash<std::string>{}(s.last_name); return h1 ^ (h2 << 1); // 或使用 boost::hash_combine } }; // std::hash 的自定义特化可以注入到 std 命名空间中。 template<> struct std::hash<S> { std::size_t operator()(const S& s) const noexcept { std::size_t h1 = std::hash<std::string>{}(s.first_name); std::size_t h2 = std::hash<std::string>{}(s.last_name); return h1 ^ (h2 << 1); // 或使用 boost::hash_combine } }; int main() { std::string str = "Meet the new boss..."; std::size_t str_hash = std::hash<std::string>{}(str); std::cout << "hash(" << std::quoted(str) << ") =\t" << str_hash << '\n'; S obj = {"Hubert", "Farnsworth"}; // 使用独立的函数对象。 std::cout << "hash(" << std::quoted(obj.first_name) << ", " << std::quoted(obj.last_name) << ") =\t" << MyHash{}(obj) << " (使用 MyHash) 或\n\t\t\t\t" << std::hash<S>{}(obj) << " (使用注入的特化)\n"; // 自定义哈希使得可以在无序容器中使用自定义类型。 // 此示例将使用上面注入的 std::hash<S> 特化, // 若要改用 MyHash,请将其作为第二个模板参数传递。 std::unordered_set<S> names = {obj, {"Bender", "Rodriguez"}, {"Turanga", "Leela"}}; for (auto const& s: names) std::cout << std::quoted(s.first_name) << ' ' << std::quoted(s.last_name) << '\n'; }
可能的输出:
hash("Meet the new boss...") = 10656026664466977650
hash("Hubert", "Farnsworth") = 12922914235676820612 (using MyHash) or
12922914235676820612 (using injected specialization)
"Bender" "Rodriguez"
"Turanga" "Leela"
"Hubert" "Farnsworth"
缺陷报告
下列行为变更缺陷报告被追溯应用于先前发布的 C++ 标准。
| 缺陷报告 | 适用版本 | 发布时行为 | 正确行为 |
|---|---|---|---|
| LWG 2119 | C++11 | 缺少对扩展整数类型的特化 | 已提供 |
| LWG 2148 | C++11 | 缺少对枚举类型的特化 | 已提供 |
| LWG 2543 | C++11 |
std::hash
可能不支持 SFINAE
|
已支持 SFINAE |
| LWG 2817 | C++11 | 缺少对 std::nullptr_t 的特化 | 已提供 |