I have the following class with an unordered_map
member, and a hash function defined for pair<int,int>
class abc {public : unordered_map < pair<int,int> , int > rules ; unsigned nodes; unsigned packet ; }; namespace std { template <> class hash < std::pair< int,int> >{ public : size_t operator()(const pair< int, int> &x ) const { size_t h = std::hash<int>()(x.first) ^ std::hash<int>()(x.second); return h ; } }; }
But I am getting the following errors :
error: invalid use of incomplete type ‘struct std::hash<std::pair<int, int> > error: declaration of ‘struct std::hash<std::pair<int, int> > error: type ‘std::__detail::_Hashtable_ebo_helper<1, std::hash<std::pair<int, int> >, true>’ is not a direct base of ‘std::__detail::_Hash_code_base<std::pair<int, int>, std::pair<const std::pair<int, int>, int>, std::__detail::_Select1st, std::hash<std::pair<int, int> >, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, true>’
Unordered Map does not contain a hash function for a pair like it has for int, string, etc, So if we want to hash a pair then we have to explicitly provide it with a hash function that can hash a pair.
However, std::pair is not hashable by default, so a simple snippet like the above would not work. There are many proposals online to define a pairhash class and explicitly specify it as the hash function as a template parameter to std::unordered_set and std::unordered_map . This is not a bad idea.
The unordered_map::hash_function() is a built in function in C++ STL which is used to get the hash function. This hash function is a unary function which takes a single argument only and returns a unique value of type size_t based on it.
Unfortunately, this program has undefined behavior. C++11 §17.6.4.2.1:
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.
hash<pair<int,int>>
depends on primitive and standard library types only. This is easily worked around by defining your hash class outside of namespace std
, and using that hash explicitly in your map declaration:
struct pairhash { public: template <typename T, typename U> std::size_t operator()(const std::pair<T, U> &x) const { return std::hash<T>()(x.first) ^ std::hash<U>()(x.second); } }; class abc { std::unordered_map<std::pair<int,int>, int, pairhash> rules; };
EDIT: I've used xor to combine the hashes of the pair members here because I'm lazy, but for serious use xor is a fairly crappy hash combining function.
I prefer to rely on the standard implementation of std::hash<uintmax_t>
to mix hashes of components of an std::pair
:
#include <functional> #include <utility> struct hash_pair final { template<class TFirst, class TSecond> size_t operator()(const std::pair<TFirst, TSecond>& p) const noexcept { uintmax_t hash = std::hash<TFirst>{}(p.first); hash <<= sizeof(uintmax_t) * 4; hash ^= std::hash<TSecond>{}(p.second); return std::hash<uintmax_t>{}(hash); } };
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