- C++17 STL Cookbook
- Jacek Galowicz
- 376字
- 2025-04-04 19:00:06
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.
- We first include what's needed in order to print and use std::unordered_map.
#include <iostream>
#include <unordered_map>
- Then we define our own custom struct, which is not trivially hashable by existing hash functions:
struct coord {
int x;
int y;
};
- 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;
}
- 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;
- 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);
}
};
}
- 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';
}
- Compiling and running the program yields the following output:
$ ./custom_type_unordered_map
{(2, 1): 3} {(0, 1): 2} {(0, 0): 1}