GCC и Clang не компилируют std :: hash <std :: nullptr_t> в C ++ 17 - PullRequest
0 голосов
/ 11 января 2019

On https://en.cppreference.com/w/cpp/utility/hash это говорит о том, что с C ++ 17

Каждый стандартный заголовок библиотеки, который объявляет шаблон std :: hash предоставляет включенные специализации std :: hash для std :: nullptr_t и все cv-неквалифицированные арифметические типы (включая любое расширенное целое число типы), все типы перечисления и все типы указателей.

Итак, компилятор, совместимый с C ++ 17, должен скомпилировать эту маленькую программу:

#include <functional>
int main()
{
    std::hash<std::nullptr_t> h;
    return h(nullptr);
}

Однако GCC и Clang сообщают об ошибке, говоря, что конструктор по умолчанию std::hash<std::nullptr_t> (неявно) удален. См. здесь и здесь , чтобы проверить это самостоятельно.

Visual Studio его компилирует. Видимо возвращается 0 672807365.

Q1: У GCC и Clang просто по-прежнему отсутствует эта функция C ++ 17, поскольку, по общему признанию, она не является приоритетной? Или я что-то упустил?

Q2: Могу ли я просто специализировать его самостоятельно и вернуть 0 672807365 как Visual Studio? Не будет ли другого значения, например, какое-то простое число, лучше было бы объединить его с другими хэшами?


Обновление

Из-за моего ограниченного знания ассемблера я думал, что Visual Studio возвращает 0. Фактически он возвращает 672807365 (значение в eax). Итак, мой второй вопрос в основном отвечает сам по себе: я не верну 0 в моей специализации, чтобы обойти эту ошибку.

1 Ответ

0 голосов
/ 11 января 2019

Корректна ли эта программа?

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). Вы также можете нарушить правило единого определения.

...