C++17 STL Cookbook
上QQ阅读APP看书,第一时间看更新

How to do it...

In this section, we will define a simple coord struct, which has no default hash function, so we need to define it ourselves. Then we put it to use by mapping coord values to numbers.

  1. We first include what's needed in order to print and use std::unordered_map.
      #include <iostream>
#include <unordered_map>
  1. Then we define our own custom struct, which is not trivially hashable by existing hash functions:
      struct coord {
int x;
int y;
};
  1. We do not only need a hash function in order to use the structure as a key for a hash map, it also needs a comparison operator implementation:
      bool operator==(const coord &l, const coord &r)
{
return l.x == r.x && l.y == r.y;
}
  1. In order to extend the STL's own hashing capabilities, we will open the std namespace and create our own std::hash template struct specialization. It contains the same using type alias clauses as other hash specializations.
      namespace std
{

template <>
struct hash<coord>
{
using argument_type = coord;
using result_type = size_t;
  1. The meat of this struct is the operator() definition. We are just adding the numeric member values of struct coord, which is a poor hashing technique, but for the sake of showing how to implement it, it's good enough. A good hash function tries to distribute values as evenly over the whole value range as possible, in order to reduce the amount of hash collisions.
          result_type operator()(const argument_type &c) const
{
return static_cast<result_type>(c.x)
+ static_cast<result_type>(c.y);
}
};

}
  1. We can now instantiate a new std::unordered_map instance, which accepts struct coord instances as a key, and maps it to arbitrary values. As this recipe is about enabling our own types for std::unordered_map, this is pretty much it already. Let's instantiate a hash-based map with our own type, fill it with some items, and print its :
      int main()
{

std::unordered_map<coord, int> m {{{0, 0}, 1}, {{0, 1}, 2},
{{2, 1}, 3}};

for (const auto & [key, value] : m) {
std::cout << "{(" << key.x << ", " << key.y
<< "): " << value << "} ";
}
std::cout << '\n';
}
  1. Compiling and running the program yields the following output:
      $ ./custom_type_unordered_map
{(2, 1): 3} {(0, 1): 2} {(0, 0): 1}