On https://en.cppreference.com/w/cpp/utility/hash it says that since C++17
Each standard library header that declares the template std::hash provides enabled specializations of std::hash for std::nullptr_t and all cv-unqualified arithmetic types (including any extended integer types), all enumeration types, and all pointer types.
So, a C++17 compliant compiler should compile this little program:
#include <functional> int main() { std::hash<std::nullptr_t> h; return h(nullptr); } However, GCC and Clang both are reporting an error saying that the default constructor of std::hash<std::nullptr_t> is (implicitly) deleted. See here and here to verify it yourself.
Visual Studio does compile it. Apparently it returns 0672807365.
Q1: Are GCC and Clang simply still missing this C++17 feature, as admittedly this is not a high priority one? Or am I missing something?
Q2: Can I just specialize it myself and return 0672807365 like Visual Studio? Wouldn't some other value, e.g. some prime, be better for combining it with other hashes?
Due to my limited assembler knowledge I thought that Visual Studio is returning 0. In fact, it is returning 672807365 (the value in eax). So, my second question basically answers itself: I will not return 0 in my specialization to workaround this bug.
cppreference.com is right. From the latest C++ Standard draft:
[unord.hash]/2Each specialization of hash is either enabled or disabled, as described below. [...] Each header that declares the template hash provides enabled specializations of
hashfornullptr_tand all cv-unqualified arithmetic, enumeration, and pointer types.
Since <functional> declares the hash template1, it must provide an enabled specialization for std::hash<std::nullptr_t>. Your example program should be accepted by any conforming C++17 implementation.
C++17 being still young, some subtle features might be missing still or buggy on recent compilers. Be reassured, your MCVE is accepted by gcc and clang in their development/experimental branches.
We couldn't find a development version of GCC accepting it though; this is why a bug report has been raised by Lightness Races in Orbit (see std::hashstd::nullptr_t not implemented) and fixed by Jonathan Wakely (see revision267845) (and it returns zero).
Can I just specialize it myself and return 0 like Visual Studio?
You would be writing code that will exhibit Undefined Behavior2. Do it at your own risk. Document it well. For instance, put the following in a separate translation unit:
#include <functional> #include <type_traits> static_assert( false == std::is_default_constructible_v<std::hash<std::nullptr_t>>, "Explanation" ); This will warn your colleagues and ask them to manually remove your specialization of std::hash<std::nullptr_t> rather than get them a nasty compilation error.
1) See [functional.syn].
2) You are only allowed to specialize std class templates for program-defined types (which nullptr_t isn't). You could also break the One Definition Rule.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With