
Klemens Morgenstern wrote:
Another example that I would be interested in is how one would hash a `boost::json::value`.
Good suggestion, thanks. In theory, this is how one would do it: namespace boost { namespace json { template<class Hash, class Flavor> void tag_invoke( boost::hash2::hash_append_tag const&, Hash& h, Flavor const& f, boost::json::value const& v ) { boost::json::visit( [&](auto const& w){ boost::hash2::hash_append( h, f, w ); }, v ); } } // namespace json } // namespace boost Unfortunately though, this doesn't work as-is for subtle reasons, and I wonder whether I need to change the tag_invoke signature somewhat so that I can prevent these errors from happening. The problem here is that boost::json::value is implicitly constructible from many things, which makes the above tag_invoke overload also match those many things in addition to json::value. (We want it to only match json::value and nothing else.) The correct way to write the tag_invoke overload today is namespace boost { namespace json { template<class Hash, class Flavor, class V> std::enable_if_t< std::is_same<V, boost::json::value>::value > tag_invoke( boost::hash2::hash_append_tag const&, Hash& h, Flavor const& f, V const& v ) { boost::json::visit( [&](auto const& w){ boost::hash2::hash_append( h, f, w ); }, v ); } } // namespace json } // namespace boost The other subtlety here is that boost::json::object should be considered an unordered range, rather than an ordinary range. It doesn't expose a `hasher` typedef, which is the heuristic is_unordered_range uses, but it already specializes is_unordered_range here: https://github.com/boostorg/json/blob/7f0bceb81280df758c7b4a7cacf8779351ebcc... so we're covered.