适用于任何枚举类型的C++11哈希函数

C++11 Hash function for any enum type

本文关键字:C++11 哈希 函数 类型 任何 枚举 适用于      更新时间:2023-10-16

我正在为我的对象编写一个哈希函数。我已经可以对容器进行散列,并组合散列,这要归功于所有STL容器的Generic hash函数。但是我的类也有枚举。当然,我可以为每个枚举创建一个散列函数,但这似乎不是一个好主意。是否可以为std::hash创建一些通用规范,以便将其应用于每个枚举?类似的东西,使用std::enable_ifstd::is_enum

namespace std {
  template <class E>
  class hash<typename std::enable_if<std::is_enum<E>::value, E>::type> {
  public:
    size_t operator()( const E& e ) const {
      return std::hash<std::underlying_type<E>::type>()( e );
    }
  };
};

PS。此代码不编译

error: template parameters not used in partial specialization:
error:         ‘E’

无法推导出E参数,因为编译器无法知道enable_if<...>::type最终会再次表示E(事实上,它的一些特殊化在设计上并没有做到这一点!)。它被称为E的"非推导上下文"。

如果hash只有一个参数,就没有办法(据我所知)对您的部分专业化进行SFINAE。

如果您愿意使用宏,可以在枚举声明旁边转储正确的std::hash专用化。

否则,我发现的唯一容易散列枚举值的方法就是泛化散列类型:

struct enum_hash
{
    template <typename T>
    inline
    typename std::enable_if<std::is_enum<T>::value, std::size_t>::type
    operator ()(T const value) const
    {
        return static_cast<std::size_t>(value);
    }
};

并以这种方式使用:

enum class E { a, b, c };
std::unordered_map<E, std:string, enum_hash> map;
map[E::a] = "a";

标准禁止您尝试做的事情。

〔namespace.std〕

如果C++程序添加声明或命名空间std或命名空间std中的命名空间的定义除非另有规定。

程序可以为任何仅当声明取决于用户定义的类型,专业化满足原始模板的标准库要求,而不是明确禁止。

因此,您当然可以追求这些答案中的一些想法,但不能称之为std::hash。定义自己的"enum_hash"模板似乎是个好主意。