为类模板的枚举成员定义std :: hash

时间:2016-02-20 01:38:18

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

假设我们有以下课程:

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?

1 个答案:

答案 0 :(得分:4)

typename S<3>::E表示特定类型。可以为该类型声明std::hash的显式特化。如果该类型曾被用作std::hash的模板参数,那么将使用您的显式特化。

另一方面,你的部分专业化无法实现

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

可以使用。正如错误所述,i不能被推导出来。对于任何给定的T,编译器无法确定std::hash<T>是否应该使用您的部分特化,因为它无法确定是否存在itypename S<i>::E是相同的输入T。如果在推断的上下文中使用了i,例如:

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

它会有所不同,因为编译器可以简单地尝试推导i。编译器可以确定确定给定类型是S<i>,其中S是已知的模板。如果某些T的{​​{1}}为S<i>,则扣除成功,否则失败并忽略专门化。在非推导的上下文中,编译器无法告诉。

如何解决?如果i是类类型,我建议将其设置为不会嵌套在E内的模板。然后,您可以为S专门设置std::hash。但是,您无法使用枚举模板,因此无法使用。您可能只有一个非模板枚举和该类型的哈希特化,然后E<i>是所有S<i>::E的枚举的typedef。如果您不希望用户依赖i所有S<i>::E的类型相同的事实,则可以说i的定义未指定。