How to specialize std::hash<Key>::operator() for user-defined type in unordered containers?
Solution 1:
You are expressly allowed and encouraged to add specializations to namespace std
*. The correct (and basically only) way to add a hash function is this:
namespace std {
template <> struct hash<Foo>
{
size_t operator()(const Foo & x) const
{
/* your code here, e.g. "return hash<int>()(x.value);" */
}
};
}
(Other popular specializations that you might consider supporting are std::less
, std::equal_to
and std::swap
.)
*) as long as one of the involved types is user-defined, I suppose.
Solution 2:
My bet would be on the Hash template argument for the unordered_map/unorder_set/... classes:
#include <unordered_set>
#include <functional>
struct X
{
int x, y;
std::size_t gethash() const { return (x*39)^y; }
};
typedef std::unordered_set<X, std::size_t(*)(const X&)> Xunset;
typedef std::unordered_set<X, std::function<std::size_t(const X&)> > Xunset2;
int main()
{
auto hashX = [](const X&x) { return x.gethash(); };
Xunset my_set (0, hashX);
Xunset2 my_set2(0, hashX); // if you prefer a more flexible set typedef
}
Of course
- hashX could just as well be a global static function
- in the second case, you could pass that
- the oldfashioned functor object (
struct Xhasher { size_t operator(const X&) const; };
) std::hash<X>()
- any bind expression satisfying the signature -
- the oldfashioned functor object (
Solution 3:
@Kerrek SB has covered 1) and 3).
2) Even though g++ and VC10 declare std::hash<T>::operator()
with different signatures, both library implementations are Standard compliant.
The Standard does not specify the members of std::hash<T>
. It just says that each such specialization must satisfy the same "Hash" requirements needed for the second template argument of std::unordered_set
and so on. Namely:
- Hash type
H
is a function object, with at least one argument typeKey
. -
H
is copy constructible. -
H
is destructible. - If
h
is an expression of typeH
orconst H
, andk
is an expression of a type convertible to (possiblyconst
)Key
, thenh(k)
is a valid expression with typesize_t
. - If
h
is an expression of typeH
orconst H
, andu
is an lvalue of typeKey
, thenh(u)
is a valid expression with typesize_t
which does not modifyu
.