By sebrockm


2019-01-11 13:12:49 8 Comments

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?


Update

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.

1 comments

@YSC 2019-01-11 13:40:31

Is this program correct?

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 for nullptr_­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.


Why it is not though?

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::hash not implemented) and fixed by Jonathan Wakely (see revision267845) (and it returns zero).


How to fix your program while you're waiting for your implementation to get fixed?

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.

Related Questions

Sponsored Content

3 Answered Questions

[SOLVED] Native path separator bug in C++17 std::filesystem::path?

1 Answered Questions

[SOLVED] Setup Clang on Travis CI for C++17

0 Answered Questions

fatal error: 'charconv' file not found in clang 6.0 with -std=c++17

0 Answered Questions

1 Answered Questions

[SOLVED] extern array as non-type template argument with clang c++1z

  • 2016-07-01 13:44:36
  • Ryhor Spivak
  • 364 View
  • 3 Score
  • 1 Answer
  • Tags:   c++ clang c++17

2 Answered Questions

[SOLVED] Cannot view std::string when compiled with clang

  • 2017-01-19 15:24:30
  • Adrian
  • 2981 View
  • 6 Score
  • 2 Answer
  • Tags:   gcc gdb clang++

1 Answered Questions

[SOLVED] C++11: SFINAE in template parameters, GCC vs Clang

1 Answered Questions

Sponsored Content