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 0
672807365
.
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 0
672807365
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]/2
Each specialization of hash is either enabled or disabled, as described below. [...] Each header that declares the template hash provides enabled specializations of
hash
fornullptr_t
and 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