Обеспечивает ли libc ++ спецификацию хеш-функций для слишком многих базовых_строк? - PullRequest
1 голос
/ 27 июня 2019

За [string.view.synop] :

// ...

// [string.view.hash], hash support
template<class T> struct hash;
template<> struct hash<string_view>;
template<> struct hash<u16string_view>;
template<> struct hash<u32string_view>;
template<> struct hash<wstring_view>;

// ...

Только для четырех "общих" basic_string_view с разрешена специализация hash. У остальных basic_string_view их hash отключены.

За [unord.hash] / 2 :

[...] Для любого типа Key, для которого ни библиотека, ни пользователь обеспечивает явную или частичную специализацию шаблона класса hash, hash<Key> отключено.

За [unord.hash] / 4 :

Если H является отключенной специализацией hash, эти значения ложны: is_­default_­constructible_­v<H>, is_­copy_­constructible_­v<H>, is_­move_­constructible_­v<H>, is_­copy_­assignable_­v<H> и is_­move_­assignable_­v<H>. Отключенные специализации hash не функциональные типы объектов. [ Примечание: Это означает, что Специализация хэша существует, но любые попытки использовать его как Hash будет плохо сформирован. & Mdash; Конечная нота ]

Следовательно, следующий минимальный воспроизводимый пример не должен компилироваться, поскольку он пытается по умолчанию создать отключенную специализацию hash:

#include <string_view>

// trait is a char trait distinct from std::char_traits<char>
struct trait :std::char_traits<char> {
    using char_traits<char>::char_traits;
};

int main()
{
    [[maybe_unused]] std::hash<std::basic_string_view<char, trait>> x;
}

Однако, это компилирует отлично на Clang 8.0.0. Копаясь в источнике libc ++, мы видим :

// [string.view.hash]
template<class _CharT, class _Traits>
struct _LIBCPP_TEMPLATE_VIS hash<basic_string_view<_CharT, _Traits> >
    : public unary_function<basic_string_view<_CharT, _Traits>, size_t>
{
    _LIBCPP_INLINE_VISIBILITY
    size_t operator()(const basic_string_view<_CharT, _Traits> __val) const _NOEXCEPT {
        return __do_string_hash(__val.data(), __val.data() + __val.size());
    }
};

Таким образом, libc ++ фактически включает hash для всех basic_string_view с.

Поэтому я делаю вывод, что это ошибка в libc ++. Является ли мой анализ правильным?

1 Ответ

4 голосов
/ 27 июня 2019

Вы правы. Libc ++ корректно отключает ваш хэш для std::basic_string, но не для std::basic_string_view.

Позже: исправлено для LLVM 9.0

...