You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用enum作为unordered_map的pair键时自定义hash遇类型转换错误

问题:枚举类作为pair键时unordered_map哈希实现报错

我想将std::pair作为std::unordered_map的键,但标准库默认未提供该类型的哈希实现,因此参考boost的hash API自行实现了一套,却遇到编译错误。

实例化map的代码如下:

using pair = std::pair<Values, std::string>;
std::unordered_map<pair, int, custom_hash<pair>> mp;

使用方式:

void Foo(Values firstKey, std::string secKey, int value)
{
    mp.insert({{firstKey, secKey}, value});
}

由于Values是枚举类,编译时报错:

could not convert 'val' from 'Values' to 'std::__hash_enum<Values, true>'.

这是否意味着模板参数T不能是枚举类型?

完整示例代码:

template <class T>
std::size_t hash_value(T val)
{
    return std::hash<T>(val);
}

template <class T>
inline void hash_combine( std::size_t& seed, T const& v)
{
    custom_hash<T>()(v);
}

template <class A, class B>
std::size_t hash_value(std::pair<A, B> const& v)
{
  std::size_t seed = 0;

  hash_combine(seed, v.first);
  hash_combine(seed, v.second);

  return seed;
}

template <class T> struct custom_hash
{
    typedef T argument_type;
    typedef std::size_t result_type;

    std::size_t operator()(T const& val) const
    {
        return hash_value(val);
    }
};

enum class Values
{
    one
};

using pair = std::pair<Values, std::string>;
std::unordered_map<pair, int, custom_hash<pair>> mp;

void Foo(Values firstKey, std::string secKey, int value)
{
    mp.insert({{firstKey, secKey}, value});
}

问题分析与修复

错误并非因为模板参数不能是枚举类型,而是你的哈希实现存在两处关键问题:

  1. hash_value函数调用错误:std::hash<T>是类模板,你需要先创建实例再调用其operator()。原代码中std::hash<T>(val)试图将val转换为std::hash<T>类型,这是完全错误的,也是编译报错的直接原因。

  2. hash_combine未执行哈希合并:原函数仅调用了哈希计算,但未将结果与传入的seed进行组合,导致所有pair的哈希值始终为0,完全失去哈希的意义。

修复后的代码

#include <functional>
#include <string>
#include <unordered_map>
#include <utility>

template <class T>
std::size_t hash_value(T const& val)
{
    // 正确调用std::hash的operator()
    return std::hash<T>{}(val);
}

template <class T>
inline void hash_combine(std::size_t& seed, T const& v)
{
    // 使用boost推荐的哈希组合算法,将新哈希值合并到seed中
    seed ^= hash_value(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}

template <class A, class B>
std::size_t hash_value(std::pair<A, B> const& v)
{
    std::size_t seed = 0;

    hash_combine(seed, v.first);
    hash_combine(seed, v.second);

    return seed;
}

template <class T> struct custom_hash
{
    using argument_type = T;
    using result_type = std::size_t;

    std::size_t operator()(T const& val) const
    {
        return hash_value(val);
    }
};

enum class Values
{
    one
};

using pair = std::pair<Values, std::string>;
std::unordered_map<pair, int, custom_hash<pair>> mp;

void Foo(Values firstKey, std::string secKey, int value)
{
    mp.insert({{firstKey, secKey}, value});
}

补充说明

C++11及以上标准中,std::hash已经原生支持枚举类型(包括强类型枚举enum class),因此无需额外为Values编写特化的哈希函数,只要正确调用std::hash即可。


内容的提问来源于stack exchange,提问作者xyf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 07:05:21