typename S<3>::E
denotes a particular type. It is fine to declare an explicit specialization of std::hash
for that type. If that type is ever used as a template argument to std::hash
, then your explicit specialization will be used.
On the other hand, there is no way that your partial specialization
template<int i>
struct hash<typename S<i>::E>
can ever be used. As the error says, i
is not deducible. For any given T
, the compiler cannot determine whether std::hash<T>
should use your partial specialization because it has no way of telling whether there exists an i
such that typename S<i>::E
is the same type as T
. If i
were used in a deduced context, such as:
template<int i>
struct hash<S<i>>
it would be different, because then the compiler could simply attempt to deduce i
. The compiler can know for sure whether a given type is S<i>
where S
is a template known to it. If T
is S<i>
for some i
, then the deduction succeeds, otherwise it fails and the specialization is ignored. In a non-deduced context, the compiler can't tell.
How to fix? If E
were a class type, I would suggest making it a template that would not be nested inside S
. Then you could specialize std::hash
for E<i>
. However, you can't have enum templates, so that's out. You could perhaps just have a single non-template enum and a hash specialization for that type, then have S<i>::E
be a typedef to that enum for all i
. If you don't want users to rely on the fact that S<i>::E
is the same type for all i
, you can just say that the definition of S<i>::E
is unspecified.