10

我正在为我的对象编写一个哈希函数。由于所有 STL-containers 的 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’
4

3 回答 3

11

E无法推断出您的参数,因为编译器无法知道您enable_if<...>::type最终会E再次表示(事实上,它的一些专业化设计不这样做!)。对于E.

如果hash只有一个参数,就没有办法(据我所知)将 SFINAE 排除在您的部分专业化之外。

于 2012-03-10T12:14:34.907 回答
4

如果您愿意使用宏,您可以在枚举声明旁边转储正确的 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";
于 2013-07-12T19:17:58.137 回答
2

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

[命名空间.std]

除非另有说明,否则如果 C++ 程序将声明或定义添加到命名空间 std 或命名空间 std 内的命名空间,则 C++ 程序的行为是未定义的。

只有当声明依赖于用户定义的类型并且特化满足原始模板的标准库要求并且没有明确禁止时,程序才能将任何标准库模板的模板特化添加到命名空间 std。

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

于 2014-04-26T14:01:02.900 回答