std::hash
来自 cppreference.com
在头文件 <bitset> 中定义 |
||
在头文件 <coroutine> 中定义 |
||
在头文件 <chrono> 中定义 |
(自 C++26 起) |
|
在头文件 <filesystem> 中定义 |
||
在头文件 <functional> 中定义 |
||
在头文件 <memory> 中定义 |
||
在头文件 <optional> 中定义 |
||
在头文件 <stacktrace> 中定义 |
||
在头文件 <string> 中定义 |
||
在头文件 <string_view> 中定义 |
||
在头文件 <system_error> 中定义 |
||
在头文件 <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
的对象。
- 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++20) |
[编辑] 成员函数
构造哈希函数对象 (公共成员函数) | |
计算参数的哈希值 (公共成员函数) |
[编辑] 标准库特殊化
每个声明模板 std::hash
的头文件还为以下类型提供了启用的 std::hash
特殊化
- 所有 cv 无限定 算术类型
- 所有 cv 无限定 枚举类型
- 所有 cv 无限定 指针类型
- std::nullptr_t
除此之外,一些头文件还为库类型提供了其他启用的 std::hash
特殊化(见 下文)。
对于标准库提供的除以下特殊化之外的所有
|
(自 C++17 起) |
[编辑] 库类型特殊化
对 std::coroutine_handle 的哈希支持 (类模板特化) | |
(C++11) |
对 std::error_code 的哈希支持 (类模板特化) |
对 std::error_condition 的哈希支持 (类模板特化) | |
对 std::stacktrace_entry 的哈希支持 (类模板特化) | |
对 std::basic_stacktrace 的哈希支持 (类模板特化) | |
(C++17) |
对 std::optional 的哈希支持 (类模板特化) |
(C++17) |
对 std::variant 的哈希支持 (类模板特化) |
(C++17) |
对 std::monostate 的哈希支持 (类模板特化) |
(C++11) |
对 std::bitset 的哈希支持 (类模板特化) |
(C++11) |
对 std::unique_ptr 的哈希支持 (类模板特化) |
(C++11) |
对 std::shared_ptr 的哈希支持 (类模板特化) |
(C++11) |
对 std::type_index 的哈希支持 (类模板特化) |
(C++11) |
对字符串的哈希支持 (类模板特化) |
对字符串视图的哈希支持 (类模板特化) | |
(C++11) |
对 std::vector<bool> 的哈希支持 (类模板特化) |
对 std::filesystem::path 的哈希支持 (类模板特化) | |
(C++11) |
对 std::thread::id 的哈希支持 (类模板特化) |
对 std::chrono::duration 的哈希支持 (类模板特化) | |
对 std::chrono::time_point 的哈希支持 (类模板特化) | |
(C++26) |
对 std::chrono::day 的哈希支持 (类模板特化) |
对 std::chrono::month 的哈希支持 (类模板特化) | |
(C++26) |
对 std::chrono::year 的哈希支持 (类模板特化) |
对 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 的哈希支持 (类模板特化) |
[编辑] 备注
实际的哈希函数是实现相关的,并且不需要满足除了上面指定之外的任何其他质量标准。值得注意的是,一些实现使用微不足道的(标识)哈希函数,它们将一个整数映射到它本身。换句话说,这些哈希函数旨在与无序关联容器一起使用,但并非作为加密哈希,例如。
哈希函数只需要在一个程序的单个执行中对相同的输入产生相同的结果;这允许使用盐哈希来防止碰撞拒绝服务攻击。
没有针对 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; // since C++20 }; // Before C++20. // bool operator==(const S& lhs, const S& rhs) // { // return lhs.first_name == rhs.first_name && lhs.last_name == rhs.last_name; // } // Custom hash can be a standalone function object. 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); // or use boost::hash_combine } }; // Custom specialization of std::hash can be injected in namespace 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); // or use 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"}; // Using the standalone function object. std::cout << "hash(" << std::quoted(obj.first_name) << ", " << std::quoted(obj.last_name) << ") =\t" << MyHash{}(obj) << " (using MyHash) or\n\t\t\t\t" << std::hash<S>{}(obj) << " (using injected specialization)\n"; // Custom hash makes it possible to use custom types in unordered containers. // The example will use the injected std::hash<S> specialization above, // to use MyHash instead, pass it as a second template argument. 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++ 标准。
DR | 应用于 | 已发布的行为 | 正确的行为 |
---|---|---|---|
LWG 2119 | C++11 | 缺少扩展整数类型的特化 | 已提供 |
LWG 2148 | C++11 | 缺少枚举类型的特化 | 已提供 |
LWG 2543 | C++11 | std::hash 可能不适合 SFINAE |
已改为适合 SFINAE |
LWG 2817 | C++11 | 缺少 std::nullptr_t 的特化 | 已提供 |