//// Copyright 2005-2008 Daniel James Copyright 2022 Christian Mazakas Copyright 2022 Peter Dimov Distributed under the Boost Software License, Version 1.0. https://www.boost.org/LICENSE_1_0.txt //// [#combine] = Combining Hash Values :idprefix: combine_ Say you have a point class, representing a two dimensional location: [source] ---- class point { int x; int y; public: point() : x(0), y(0) {} point(int x, int y) : x(x), y(y) {} bool operator==(point const& other) const { return x == other.x && y == other.y; } }; ---- and you wish to use it as the key for an `unordered_map`. You need to customise the hash for this structure. To do this we need to combine the hash values for `x` and `y`. The function `boost::hash_combine` is supplied for this purpose: [source] ---- class point { ... friend std::size_t hash_value(point const& p) { std::size_t seed = 0; boost::hash_combine(seed, p.x); boost::hash_combine(seed, p.y); return seed; } ... }; ---- Calls to `hash_combine` incrementally build the hash from the different members of `point`, it can be repeatedly called for any number of elements. It calls `hash_value` on the supplied element, and combines it with the seed. Full code for this example is at link:../../examples/point.cpp[examples/point.cpp]. Note that when using `boost::hash_combine` the order of the calls matters. [source] ---- std::size_t seed = 0; boost::hash_combine(seed, 1); boost::hash_combine(seed, 2); ---- and [source] ---- std::size_t seed = 0; boost::hash_combine(seed, 2); boost::hash_combine(seed, 1); ---- result in a different values in `seed`. To calculate the hash of an iterator range you can use `boost::hash_range`: [source] ---- std::vector some_strings; std::size_t hash = boost::hash_range(some_strings.begin(), some_strings.end()); ---- Since `hash_range` works by repeatedly invoking `hash_combine` on the elements of the range, the hash value will also be dependent on the element order. If you are calculating a hash value for a range where the order of the data doesn't matter, such as `unordered_set`, you can use `boost::hash_unordered_range` instead. [source] ---- std::unordered_set set; std::size_t hash = boost::hash_unordered_range(set.begin(), set.end()); ---- When writing template classes, you might not want to include the main `hash.hpp` header as it's quite an expensive include that brings in a lot of other headers, so instead you can include the `` header which forward declares `boost::hash`, `boost::hash_combine`, `boost::hash_range`, and `boost::hash_unordered_range`. You'll need to include the main header before instantiating `boost::hash`. When using a container that uses `boost::hash` it should do that for you, so your type will work fine with the Boost hash containers. There's an example of this in link:../../examples/template.hpp[examples/template.hpp] and link:../../examples/template.cpp[examples/template.cpp]. To avoid including even `hash_fwd.hpp` - which still requires the contents of Boost.ContainerHash to be physically present - you are allowed to copy the declarations from `hash_fwd.hpp` (and only those) directly into your own header. This is a special exception guaranteed by the library; in general, you can't declare library functions, Boost or otherwise, without risk of breakage in a subsequent release.