libc++ 是否为太多 basic_string_view 提供散列专业化?

Is libc++ providing hash specialization for too many basic_string_view's?

根据 [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>;

// ...

只有四个 "common" basic_string_view 启用了 hash 的特化。其他 basic_string_view 已禁用其 hashes。

根据 [unord.hash]/2:

[...] For any type Key for which neither the library nor the user provides an explicit or partial specialization of the class template hash, hash<Key> is disabled.

根据 [unord.hash]/4:

If H is a disabled specialization of hash, these values are false: is_­default_­constructible_­v<H>, is_­copy_­constructible_­v<H>, is_­move_­constructible_­v<H>, is_­copy_­assignable_­v<H>, and is_­move_­assignable_­v<H>. Disabled specializations of hash are not function object types. [ Note: This means that the specialization of hash exists, but any attempts to use it as a Hash will be ill-formed. — end note ]

因此,不应编译以下最小可重现示例,因为它试图默认构造 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;
}

然而,这编译 fine on Clang 8.0.0. Digging down the source of libc++, we see:

// [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++ 实际上为所有 basic_string_view 启用了 hash

因此,我断定这是libc++的一个bug。我的分析正确吗?

看来你是对的。 Libc++ 正确地禁用了 std::basic_string 的散列,但不是 std::basic_string_view.

后来:修复了 LLVM 9.0