std:: hash
|
定义于头文件
<bitset>
|
||
|
定义于头文件
<coroutine>
|
(C++20 起)
|
|
|
定义于头文件
<chrono>
|
(C++26 起)
|
|
|
定义于头文件
<filesystem>
|
(C++17 起)
|
|
|
定义于头文件
<functional>
|
||
|
定义于头文件
<memory>
|
||
|
定义于头文件
<optional>
|
(C++17 起)
|
|
|
定义于头文件
<stacktrace>
|
(C++23 起)
|
|
|
定义于头文件
<string>
|
||
|
定义于头文件
<string_view>
|
(C++17 起)
|
|
|
定义于头文件
<system_error>
|
||
|
定义于头文件
<text_encoding>
|
(C++26 起)
|
|
|
定义于头文件
<thread>
|
||
|
定义于头文件
<typeindex>
|
||
|
定义于头文件
<utility>
|
(C++26 起)
|
|
|
定义于头文件
<variant>
|
(C++17 起)
|
|
|
定义于头文件
<vector>
|
||
|
template
<
class
Key
>
struct hash ; |
(C++11 起) | |
hash
模板的启用特化定义了一个实现
哈希函数
的函数对象。
给定类型
Key
,每个特化
std::hash<Key>
要么处于
启用
状态,要么处于
禁用
状态:
-
如果程序或用户未提供
std::hash<Key>,则该功能被禁用。 -
否则,当满足以下所有条件时,
std::hash<Key>将被启用:
-
- 满足以下所有要求:
-
-
Hash
(以
Key作为函数调用参数类型) - DefaultConstructible
- CopyAssignable
- Swappable
-
Hash
(以
- 给定以下值:
-
-
h
,类型为
std::hash<Key>的对象。 -
k1
和
k2
,类型为
Key的对象。
-
h
,类型为
-
满足以下所有要求:
- 若 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 >> :: value
- std:: is_copy_constructible < std :: hash < Key >> :: value
- std:: is_move_constructible < std :: hash < Key >> :: value
- std:: is_copy_assignable < std :: hash < Key >> :: value
- std:: is_move_assignable < std :: hash < Key >> :: value
标签内的C++代码均保持原样未翻译,仅对列表项前的描述性文字进行了翻译。由于原文中除代码外无其他可翻译文本内容,故仅添加了说明性注释。)
换言之,它们确实存在,但无法使用。
嵌套类型
|
(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::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 的特化 | 已提供 |