You have been taken in by a common misconception, but std::hash
is not a customization point for hashing of user-defined types. Instead, std::hash
is the default implementation of the hasher that is used by the standard containers. If you want to use the standard containers with user-defined types, then you should use their template arguments to supply a hasher.
Correct
All standard containers that require a hash function for their contents have a template argument that takes a function object whose call operator computes the hash.
#include <boost/functional/hash.hpp>
#include <unordered_set>
struct Point { int x, y; };
struct PointHasher {
size_t operator()(Point const &p) {
size_t seed = 0;
boost::hash_combine(seed, p.x);
boost::hash_combine(seed, p.y);
return seed;
}
};
int main() {
std::unordered_set<Point, PointHasher> m;
}
Wrong
Writing into namespace std
is usually undefined behaviour, see also What are the reasons that extending the std namespace is considered undefined behavior? There is an exception for template specializations under certain circumstances, but in this case it is not even necessary.
#include <boost/functional/hash.hpp>
#include <unordered_set>
struct Point { int x, y; };
namespace std {
template<> struct hash<Point> {
size_t operator()(Point const &p) {
size_t seed = 0;
boost::hash_combine(seed, p.x);
boost::hash_combine(seed, p.y);
return seed;
}
};
}
int main() {
std::unordered_set<point> m;
}