I am writing a hash function for my object. I already can hash containers, and combine hashes, thanks to Generic Hash function for all STL-containers. But my classes also have enums. Of course I can create a hash function for every enum, but it does not seem like a good idea. Is it possible to create some generic specification for std::hash
, so that it could be applied to every enum? Something like that, using std::enable_if
and std::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. This code does not compile
error: template parameters not used in partial specialization:
error: ‘E’
Your E
parameter cannot be deduced, because the compiler cannot know that your enable_if<...>::type
ends up denoting E
again (and in fact, there are some specializations of it that by design don't do that!). It's called a "non-deduced context" for E
.
If hash
has only one parameter, there is no way (that I am aware of) to SFINAE out your partial specialization.
If you're willing to use macros, you could dump the correct std::hash specialization next to your enum declaration.
Otherwise, the only way I've found to easily hash enum values is to generalize the hash type:
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);
}
};
and using it that way:
enum class E { a, b, c };
std::unordered_map<E, std:string, enum_hash> map;
map[E::a] = "a";
What you're trying to do is prohibited by the standard.
[namespace.std]
The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std unless otherwise specified.
A program may add a template specialization for any standard library template to namespace std only if the declaration depends on a user-defined type and the specialization meets the standard library requirements for the original template and is not explicitly prohibited.
So you can certainly pursue some of the ideas in these answers, but you can't call it std::hash. Defining your own 'enum_hash' template seems like a good idea.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With