【问题标题】:Define std::hash for enum member of class template为类模板的枚举成员定义 std::hash
【发布时间】:2016-02-20 01:38:17
【问题描述】:

假设我们有以下类:

template <int i>
class S {
public:
    enum class E : signed char {a, b, c};
    // ...
};

现在我想为 E 提供一个哈希函数。以下工作:

namespace std {
template<>
struct hash<typename S<3>::E> {
    size_t operator()(typename S<3>::E const& e) const { return 0; }
};
}

但如果我把它变成通用的,它就不会:

namespace std {
template<int i>
struct hash<typename S<i>::E> {
    size_t operator()(typename S<i>::E const& e) const { return 0; }
};
}
// error C2764: 'i': template parameter not used or deducible in partial specialization 'std::hash<S<i>::E>'

如何确保始终能够为所有 i 散列 S::E?

【问题讨论】:

  • 如果所有S&lt;i&gt; 都有E 是某个其他单一类型的typedef 怎么办? i 在一般意义上无法弄清楚。它并不完全相同,但这里有一些类似的答案。找到一个:stackoverflow.com/questions/6060824/…

标签: c++ hash enums c++14


【解决方案1】:

typename S&lt;3&gt;::E 表示特定类型。为该类型声明 std::hash 的显式特化很好。如果该类型曾经用作std::hash 的模板参数,那么将使用您的显式特化。

另一方面,你的部分专业化是不可能的

template<int i>
struct hash<typename S<i>::E>

永远可以使用。正如错误所说,i 是不可推断的。对于任何给定的T,编译器无法确定std::hash&lt;T&gt; 是否应该使用您的部分特化,因为它无法判断是否存在i 使得typename S&lt;i&gt;::ET 的类型相同。如果i 用于推断的上下文中,例如:

template<int i>
struct hash<S<i>>

它会有所不同,因为编译器可以简单地尝试推断i。编译器可以肯定知道给定类型是否为S&lt;i&gt;,其中S 是它已知的模板。如果T对于某些iS&lt;i&gt;,则推演成功,否则推演失败,忽略特化。在非演绎的上下文中,编译器无法判断。

如何解决?如果E 是一个类类型,我建议将其设为不会嵌套在S 中的模板。然后你可以将std::hash 专门用于E&lt;i&gt;。但是,你不能有枚举模板,所以就不行了。您可能只有一个非模板枚举和该类型的哈希特化,然后让S&lt;i&gt;::E 成为所有i 的该枚举的类型定义。如果您不希望用户依赖 S&lt;i&gt;::E 是所有 i 的同一类型这一事实,您可以说 S&lt;i&gt;::E 的定义是未指定的。

【讨论】:

  • 对。那么如何确保我始终可以为所有 i 散列 S::E?
  • 好的,谢谢。我接受这样一个事实:完全按照我的意愿去做是不可能的。
  • 我相信你也可以把E定义成一些看起来很吓人的namespace(比如臭名昭著的detail),然后把using E = detail::E;变成S。您可以专门化 std::hash&lt;detail::E&gt;,但您的用户不需要知道这一点。
  • @5gon12eder 是的,就是这样
猜你喜欢
  • 2015-12-24
  • 2014-04-22
  • 1970-01-01
  • 2016-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多