boostorg / container_hash

Generic hash function for STL style unordered containers
https://boost.org/libs/container_hash
29 stars 39 forks source link

hash_combine, hash_range, and hash_value can be constexpr #16

Open saki7 opened 3 years ago

saki7 commented 3 years ago

https://github.com/boostorg/container_hash/blob/develop/include/boost/container_hash/hash.hpp

Since most part of internal calculations are based on integer arithmetic and bitwise operations, I believe those three functions and all their variants can be marked constexpr today. Can someone please enlighten me, why the standard std::hash<T>::operator() and proposed std::hash_combine() in P0814R2 is not constexpr? (backward-compatibility, or other reasons?)

If we are to provide constexpr-ness, there are two cases of implementations:

refs: cplusplus/papers#253

pdimov commented 1 year ago

The current implementation (on develop) can in principle be constexpr; it no longer uses rotations. The problem, however, is that we support forward-declaring boost::hash_combine and boost::hash_range, so that people can add boost::hash support for their types without having to include a ContainerHash header (which would require Boost headers to be physically present even if they are otherwise not used.)

Since the forward declarations lack constexpr, it's not possible to later define the functions to be constexpr.

This is specific to boost::hash, of course, and doesn't apply to std::hash. I would guess, however, that stdlib implementers will be opposed to marking the standard functions constexpr, because this would require them to be implemented in the header, rather than out of line (as they currently tend to be.) This will make further changes to the hash functions effectively impossible because changes will break binary compatibility as the hash functions will already have been inlined into user code.

saki7 commented 1 year ago

Since std::hash is a template and it is intended to be specialized for certain types, their implementations must exist inside the header anyways. Even when there exists some hash implementations which delegate the calculation to non-template function, users would silently face an incompatible hash value when those external functions change. I suppose that kind of situation is also a binary incompatibility issue, and there's possibility for that to happen regardless of being constexpr or not.

So my question still persists: why are hash functions not constexpr in the first place, despite the fact that they are already specialized in compile-time context?