|
1 |
| -1 |
| 1 | +#include <iostream> |
| 2 | +#include <iomanip> |
| 3 | +#include <functional> |
| 4 | +#include <string> |
| 5 | +#include <unordered_set> |
| 6 | + |
| 7 | +struct S { |
| 8 | + std::string first_name; |
| 9 | + std::string last_name; |
| 10 | +}; |
| 11 | +bool operator==(const S& lhs, const S& rhs) { |
| 12 | + return lhs.first_name == rhs.first_name && lhs.last_name == rhs.last_name; |
| 13 | +} |
| 14 | + |
| 15 | +// custom hash can be a standalone function object: |
| 16 | +struct MyHash |
| 17 | +{ |
| 18 | + std::size_t operator()(S const& s) const noexcept |
| 19 | + { |
| 20 | + std::size_t h1 = std::hash<std::string>{}(s.first_name); |
| 21 | + std::size_t h2 = std::hash<std::string>{}(s.last_name); |
| 22 | + return h1 ^ (h2 << 1); // or use boost::hash_combine (see Discussion) |
| 23 | + } |
| 24 | +}; |
| 25 | + |
| 26 | +// custom specialization of std::hash can be injected in namespace std |
| 27 | +namespace std |
| 28 | +{ |
| 29 | + template<> struct hash<S> |
| 30 | + { |
| 31 | + std::size_t operator()(S const& s) const noexcept |
| 32 | + { |
| 33 | + std::size_t h1 = std::hash<std::string>{}(s.first_name); |
| 34 | + std::size_t h2 = std::hash<std::string>{}(s.last_name); |
| 35 | + return h1 ^ (h2 << 1); // or use boost::hash_combine |
| 36 | + } |
| 37 | + }; |
| 38 | +} |
| 39 | + |
| 40 | +int main() |
| 41 | +{ |
| 42 | + std::string str = "Meet the new boss..."; |
| 43 | + std::size_t str_hash = std::hash<std::string>{}(str); |
| 44 | + std::cout << "hash(" << std::quoted(str) << ") = " << str_hash << '\n'; |
| 45 | + |
| 46 | + S obj = { "Hubert", "Farnsworth" }; |
| 47 | + // using the standalone function object |
| 48 | + std::cout << "hash(" << std::quoted(obj.first_name) << ", " |
| 49 | + << std::quoted(obj.last_name) << ") = " |
| 50 | + << MyHash{}(obj) << " (using MyHash)\n" << std::setw(31) << "or " |
| 51 | + << std::hash<S>{}(obj) << " (using injected std::hash<S> specialization)\n"; |
| 52 | + |
| 53 | + // custom hash makes it possible to use custom types in unordered containers |
| 54 | + // The example will use the injected std::hash<S> specialization above, |
| 55 | + // to use MyHash instead, pass it as a second template argument |
| 56 | + std::unordered_set<S> names = {obj, {"Bender", "Rodriguez"}, {"Turanga", "Leela"} }; |
| 57 | + for(auto& s: names) |
| 58 | + std::cout << std::quoted(s.first_name) << ' ' << std::quoted(s.last_name) << '\n'; |
| 59 | +} |
0 commit comments