|
Boost : |
From: Peter Dimov (pdimov_at_[hidden])
Date: 2024-12-07 16:16:34
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:
so we're covered.
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk