假设我们有以下课程:
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?
答案 0 :(得分:4)
typename S<3>::E
表示特定类型。可以为该类型声明std::hash
的显式特化。如果该类型曾被用作std::hash
的模板参数,那么将使用您的显式特化。
另一方面,你的部分专业化无法实现
template<int i>
struct hash<typename S<i>::E>
可以使用。正如错误所述,i
不能被推导出来。对于任何给定的T
,编译器无法确定std::hash<T>
是否应该使用您的部分特化,因为它无法确定是否存在i
,typename 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
的定义未指定。