I needed a std::unordered_map
with key a std::pair<T*, T*>
so I "stole" the following code:
template <class T>
inline void hash_combine(std::size_t & seed, const T & v)
{
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
namespace std
{
template<typename S, typename T> struct hash<pair<S, T>>
{
inline size_t operator()(const pair<S, T> & v) const
{
size_t seed = 0;
::hash_combine(seed, v.first);
::hash_combine(seed, v.second);
return seed;
}
};
}
from this stackoverflow answer.
It works like a charm on linux machines with gcc 4.9.2. However in windows visual studio 2012 it crashes upon calling member function find()
of my unordered_map
. A friend of mine debugged the crash on windows machine and he reported that it breaks only in debug compilation mode by giving "vector subscript out of range".
Q:
- Is the code posted valid for hashing a
std::pair<T*, T*>
? - Is there a more robust/better way of hashing a
std::pair<T*, T*>
? - What causes this strange behaviour?
P.S: Deeply sorry for not posting a mcve but It's impossible to do so.
Specialization of templates in
std
for types also instd
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:
now you pass
my_hash::hasher<>
as your hasher to a container, and you don't have to do the sketchy business of providing astd
specialization for a type (mostly) instd
.my_hash::hasher<?,void>
exists so you can do SFINAE testing (say, detect if a type is container-like, and forward tohash_container
.my_hash::hash
provides ADL overriding for types without having to fool around in themy_hash
namespace.As an example:
and
custom
is now hashable. No messy specialization required.