I am trying to create an unordered_map to map pairs with integers.
#include <unordered_map>
using namespace std;
using Vote = pair<string, string>;
using Unordered_map = unordered_map<Vote, int>;
I have a class where I have declared an Unordered_map as a private member.
However, I am getting this error when I try to compile:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/type_traits:948:38: Implicit instantiation of undefined template 'std::__1::hash<std::__1::pair<std::__1::basic_string<char>, std::__1::basic_string<char> > >'
I am not getting this error if I use a regular map like map<pair<string, string>, int>
instead of an unordered_map.
Is it not possible to use pair
as key in unordered maps?
As your compilation error indicates, there is no valid instantiation of
std::hash<std::pair<std::string, std::string>>
in your std namespace.According to my compiler:
You can provide your own specialization for
std::hash<Vote>
as follows:You need to provide a suitable hash function for your key type. A simple example:
This will work, but not have the best hash-properties†. You might want to have a look at something like
boost.hash_combine
for higher quality results when combining the hashes.For real world use: Boost also provides the function set
hash_value
which already provides a hash function forstd::pair
, as well asstd::tuple
and most standard containers.†More precisely, it will produce too many collisions. E.g., every symmetric pair will hash to 0 and pairs that differ only by permutation will have the same hash. This is probably fine for your programming exercise, but might seriously hurt performance of real world code.
For pair key, we can use boost pair hash function:
Similarly we can use boost hash for vectors,
My preferred way of solving this problem is to define a
key
function that transforms your pair into a unique integer (or any hashable data type). This key is not the hash key. It is the unique ID of the pair of data that will then be optimally hashed by theunordered_map
. For example, you wanted to define anunordered_map
of the typeAnd you want to use
Map[make_pair(i,j)]=value
orMap.find(make_pair(i,j))
to operate on the map. Then you'll have to tell the system how to hash a pair of integersmake_pair(i,j)
. Instead of that, we can defineand then change the type of the map to
We can now use
Map[key(i,j)]=value
orMap.find(key(i,j))
to operate on the map. Everymake_pair
now becomes calling the inlinekey
function.This method guarantees that the key will be optimally hashed, because now the hashing part is done by the system, which will always choose the internal hash table size to be prime to make sure every bucket is equally likely. But you have to make yourself 100% sure that the
key
is unique for every pair, i.e., no two distinct pairs can have the same key, or there can be very difficult bugs to find.