I needed a std::unordered_map with key a std::pair so I \"stole\" the following code:
template
inline
Specialization of templates in std for types also in std may or may not make your program ill-formed (the standard is ambiguous, it seems to use "user-defined type" in multiple different ways without ever defining it). See my question on the subject, and active working group defect on the issue.
So create your own hashing namespace:
namespace my_hash {
template
struct hasher:std::hash{};
template(T const&) >>
size_t hash( T const& t ) {
return hasher{}(t);
}
template<>
struct hasher {
template
std::result_of_t(T const&)>
operator()(T const& t)const{
return hasher{}(t);
}
};
// support for containers and tuples:
template
size_t hash_combine(std::size_t seed, const T & v) {
seed ^= hash(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
return seed;
}
template
size_t hash_tuple_like(Tuple const& t, size_t count, std::index_sequence) {
size_t seed = hash(count);
using discard=int[];
(void)discard{0,((
seed = hash_combine(seed, std::get(t))
),void(),0)...};
return seed;
}
template
size_t hash_tuple_like(Tuple const& t) {
constexpr size_t count = std::tuple_size{};
return hash_tuple_like(t, count, std::make_index_sequence{} );
}
struct tuple_hasher {
template
size_t operator()(Tuple const& t)const{
return hash_tuple_like(t);
}
};
template
struct hasher,void>:
tuple_hasher
{};
template
struct hasher,void>:
tuple_hasher
{};
template
struct hasher,void>:
tuple_hasher
{};
template
size_t hash_container( C const& c ) {
size_t seed = hash(c.size());
for( const auto& x:c ) {
seed = hash_combine( seed, x );
}
return seed;
}
struct container_hasher {
template
size_t operator()(C const& c)const{ return hash_container(c); }
};
template
struct hasher< std::vector, void >:
container_hasher
{};
// etc
};
now you pass my_hash::hasher<> as your hasher to a container, and you don't have to do the sketchy business of providing a std specialization for a type (mostly) in std.
my_hash::hasher,void> exists so you can do SFINAE testing (say, detect if a type is container-like, and forward to hash_container. my_hash::hash provides ADL overriding for types without having to fool around in the my_hash namespace.
As an example:
template
struct custom {
std::vector state;
friend size_t hash( custom const& c ) {
using my_hash::hash;
return hash(state);
}
};
and custom is now hashable. No messy specialization required.