Ответ 1
Эта программа правильная?
cppreference.com прав. Из последней версии стандарта C++:
[unord.hash]/2
Каждая специализация хэша либо включена, либо отключена, как описано ниже. [...] Каждый заголовок, который объявляет хэш шаблона, предоставляет включенные специализации
hash
дляnullptr_t
и всех cv-неквалифицированных арифметических, перечислимых и указательных типов.
Так как <functional>
объявляет hash
шаблон 1 он должен предоставлять включенную специализацию для std::hash<std::nullptr_t>
. Ваша примерная программа должна быть принята любой соответствующей C++ 17 реализацией.
Почему это не так, хотя?
C++ 17, будучи еще молодым, некоторые тонкие функции могут отсутствовать или содержать ошибки в последних компиляторах. Будьте уверены, ваш MCVE принят gcc и clang в их ветки разработки /эксперимента.
Мы не смогли найти версию GCC, которая бы его принимала; именно поэтому отчет об ошибках был создан Расами Легкости на орбите (см. std :: hash не реализован) и исправлен Джонатаном Уэйкли (см. revision267845) (и он возвращает ноль).
Как исправить вашу программу, пока вы ожидаете исправления вашей реализации?
Могу ли я просто специализировать его и вернуть 0, как Visual Studio?
Вы будете писать код, который будет демонстрировать неопределенное поведение 2. Делайте это на свой страх и риск. Документируйте это хорошо. Например, поместите следующее в отдельную единицу перевода:
#include <functional>
#include <type_traits>
static_assert(
false == std::is_default_constructible_v<std::hash<std::nullptr_t>>,
"Explanation"
);
Это предупредит ваших коллег и попросит их вручную удалить вашу специализацию std::hash<std::nullptr_t>
вместо того, чтобы получить им неприятную ошибку компиляции.
1) См. [functional.syn]
.
2) Вам разрешено специализировать шаблоны классов std
для программно-определяемых типов (что не является nullptr_t
). Вы также можете нарушить правило единого определения.