std::hash
出自 cppreference.com
| 定義於標頭 <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> 特例化要么是已啟用 (enabled),要么是已停用 (disabled)
- 若
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 的雜湊支援 (class template specialization) |
| (C++11) |
std::bitset 的雜湊支援 (類別樣板特例化) |
| (C++11) |
std::unique_ptr 的雜湊支援 (類別範本特化) |
| (C++11) |
std::shared_ptr 的雜湊支援 (類別範本特化) |
| (C++11) |
std::type_index 的雜湊支援 (類別樣板特例化) |
| (C++11) |
對字串的雜湊 (hash) 支援 (類別樣板特化) |
| 字串檢視 (string views) 的雜湊支援 (類別樣板特例化) | |
| std::text_encoding 的雜湊支援 (類別樣板特例化) | |
| (C++11) |
std::vector<bool> 的雜湊支援 (class template specialization) |
| std::filesystem::path 的雜湊支援 (類別樣板特例化) | |
| (C++11) |
std::thread::id 的雜湊支援 (類別樣板特例化) |
| std::chrono::duration 的雜湊支援 (class template specialization) | |
| std::chrono::time_point 的雜湊支援 (class template specialization) | |
| (C++26) |
std::chrono::day 的雜湊支援 (class template specialization) |
| std::chrono::month 的雜湊支援 (class template specialization) | |
| (C++26) |
std::chrono::year 的雜湊支援 (class template specialization) |
| std::chrono::weekday 的雜湊支援 (class template specialization) | |
| std::chrono::weekday_indexed 的雜湊支援 (class template specialization) | |
| std::chrono::weekday_last 的雜湊支援 (class template specialization) | |
| std::chrono::month_day 的雜湊支援 (class template specialization) | |
| std::chrono::month_day_last 的雜湊支援 (class template specialization) | |
| std::chrono::month_weekday 的雜湊支援 (class template specialization) | |
| std::chrono::month_weekday_last 的雜湊支援 (class template specialization) | |
| std::chrono::year_month 的雜湊支援 (class template specialization) | |
| std::chrono::year_month_day 的雜湊支援 (class template specialization) | |
| std::chrono::year_month_day_last 的雜湊支援 (class template specialization) | |
| std::chrono::year_month_weekday 的雜湊支援 (class template specialization) | |
| std::chrono::year_month_weekday_last 的雜湊支援 (class template specialization) | |
| std::chrono::zoned_time 的雜湊支援 (class template specialization) | |
| std::chrono::leap_second 的雜湊支援 (class template specialization) |
[編輯] 備註
實際的雜湊函式取決於實作,除了上述指定的要求外,不需滿足任何其他品質標準。值得注意的是,某些實作使用簡單(恆等)雜湊函式,將整數映射至其自身。換句話說,這些雜湊函式旨在與無序關聯容器搭配使用,而非例如加密用途的雜湊。
雜湊函式僅被要求在程式的單次執行中,對相同輸入產生相同的結果;這允許使用加鹽雜湊(salted hashes)來防止拒絕服務攻擊。
沒有針對 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 的特例化 | 提供 |