命名空间
变体
操作

std::hash

来自 cppreference.cn
< cpp‎ | utility
 
 
 
 
定义于头文件 <bitset>
定义于头文件 <coroutine>
定义于头文件 <chrono>
(since C++26)
定义于头文件 <filesystem>
定义于头文件 <functional>
定义于头文件 <memory>
定义于头文件 <optional>
定义于头文件 <stacktrace>
定义于头文件 <string>
定义于头文件 <string_view>
定义于头文件 <system_error>
定义于头文件 <text_encoding>
定义于头文件 <thread>
定义于头文件 <typeindex>
定义于头文件 <variant>
定义于头文件 <vector>
template< class Key >
struct hash;
(since 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> 是启用的
  • 满足以下所有要求
  • 给定以下值
  • h,类型为 std::hash<Key> 的对象。
  • k1k2,类型为 Key 的对象。
满足以下所有要求
  • 如果 k1 == k2true,则 h(k1) == h(k2) 也为 true
  • 除非 std::hash<Key>程序定义的特化,否则 h(k1) 永远不会抛出异常。
  • 否则,std::hash<Key> 是禁用的。

禁用的特化不满足 Hash,不满足 FunctionObject,并且以下值均为 false

换句话说,它们存在,但不能使用。

内容

嵌套类型

名称 定义
argument_type (C++17 中已弃用) Key
result_type (C++17 中已弃用) std::size_t
(until C++20)

[编辑] 成员函数

构造哈希函数对象
(公共成员函数)
计算实参的哈希值
(公共成员函数)

[编辑] 标准库特化

每个声明了模板 std::hash 的头文件也为以下类型提供了 std::hash 的启用特化

除此之外,一些头文件还为库类型提供了其他启用的 std::hash 特化(见下文)。

对于标准库提供的所有 std::hash 特化,除了以下几种,它们的所有成员函数都是 noexcept

(since C++26)
(since C++17)

[编辑] 库类型的特化

std::coroutine_handle 的哈希支持
(类模板特化) [编辑]
std::error_code 的哈希支持
(类模板特化) [编辑]
std::error_condition 的哈希支持
(类模板特化) [编辑]
std::stacktrace_entry 的哈希支持
(类模板特化) [编辑]
std::basic_stacktrace 的哈希支持
(类模板特化) [编辑]
std::optional 的哈希支持
(类模板特化) [编辑]
std::variant 的哈希支持
(类模板特化) [编辑]
std::monostate 的哈希支持
(类模板特化)
std::bitset 的哈希支持
(类模板特化) [编辑]
std::unique_ptr 的哈希支持
(类模板特化) [编辑]
std::shared_ptr 的哈希支持
(类模板特化) [编辑]
std::type_index 的哈希支持
(类模板特化) [编辑]
字符串的哈希支持
(类模板特化) [编辑]
字符串视图的哈希支持
(类模板特化) [编辑]
std::text_encoding 的哈希支持
(类模板特化) [编辑]
std::vector<bool> 的哈希支持
(类模板特化)
std::filesystem::path 的哈希支持
(类模板特化) [编辑]
std::thread::id 的哈希支持
(类模板特化) [编辑]
std::chrono::duration 的哈希支持
(类模板特化)
std::chrono::time_point 的哈希支持
(类模板特化)
std::chrono::day 的哈希支持
(类模板特化)
std::chrono::month 的哈希支持
(类模板特化)
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 的特化缺失 已提供