Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

error for hash function of pair of ints

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>’ 
like image 544
Shambo Avatar asked Dec 15 '13 02:12

Shambo


People also ask

Are pairs hashable?

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.

Is std :: pair hashable?

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.

Which hash function is used in Unordered_map?

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.


2 Answers

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.

like image 100
Casey Avatar answered Oct 17 '22 04:10

Casey


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);     } }; 
like image 25
Vladimir Reshetnikov Avatar answered Oct 17 '22 03:10

Vladimir Reshetnikov