Hi,
As far as I can see, the library doesn't provide native implementation for hashing std::optional. So the recommendation from the documentation would be to declare a tag_invoke overload.
When T is a user defined type that does not fall into one of the above categories, it needs to provide its own hashing support, by defining an appropriate tag_invoke overload.
...
It can be defined as a separate free function in the namespace of X, but the recommended approach is to define it as an inline friend in the definition of X:
However, this is a bit problematic, as the user can't extend the definition of std::optional nor add new functions to the std:: namespace as it's technically UB, although something like this does work:
namespace std {
template<typename Provider, typename Hash, typename Flavor, class T>
void tag_invoke(
boost::hash2::hash_append_tag,
Provider const& pr,
Hash& h,
Flavor const& f,
std::optional<T> const* v)
{
bool const has_value{v->has_value()};
boost::hash2::hash_append(h, f, has_value);
if (has_value) {
boost::hash2::hash_append(h, f, v->value());
}
}
}
The alternative that also works is to add this definition to the boost::hash2 namespace, which feels a bit dirty:
namespace boost::hash2 {
template<typename Provider, typename Hash, typename Flavor, class T>
void tag_invoke(
boost::hash2::hash_append_tag,
Provider const& pr,
Hash& h,
Flavor const& f,
std::optional<T> const* v)
{
bool const has_value{v->has_value()};
boost::hash2::hash_append(h, f, has_value);
if (has_value) {
boost::hash2::hash_append(h, f, v->value());
}
}
}
The cleanest thing to do, would be to add the definition into some third namespace, like:
namespace my_namespace {
template<typename Provider, typename Hash, typename Flavor, class T>
void tag_invoke(
boost::hash2::hash_append_tag,
Provider const& pr,
Hash& h,
Flavor const& f,
std::optional<T> const* v)
{
bool const has_value{v->has_value()};
boost::hash2::hash_append(h, f, has_value);
if (has_value) {
boost::hash2::hash_append(h, f, v->value());
}
}
}
However, in that case, the function isn't visible by the library even if it's added to the overload set with a using statement:
int main()
{
using my_namespace::tag_invoke;
std::optional<int> value = 33;
boost::hash2::fnv1a_32 h;
boost::hash2::hash_append(h, {}, value);
auto digest = h.result();
}
Full sample code: https://godbolt.org/z/cjMx7qnnx
Maybe I'm missing something from the docs?
Thanks!
Hi,
As far as I can see, the library doesn't provide native implementation for hashing
std::optional. So the recommendation from the documentation would be to declare atag_invokeoverload.However, this is a bit problematic, as the user can't extend the definition of
std::optionalnor add new functions to thestd::namespace as it's technically UB, although something like this does work:The alternative that also works is to add this definition to the
boost::hash2namespace, which feels a bit dirty:The cleanest thing to do, would be to add the definition into some third namespace, like:
However, in that case, the function isn't visible by the library even if it's added to the overload set with a using statement:
Full sample code: https://godbolt.org/z/cjMx7qnnx
Maybe I'm missing something from the docs?
Thanks!