1

每个[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_viewhash启用的特化。其他basic_string_views 的hashes 被禁用。

根据[unord.hash]/2

[...] 对于Key库和用户都没有提供类模板的显式或部分特化的 任何类型hashhash<Key>被禁用。

根据[unord.hash]/4

如果H是 的禁用特化hash,则这些值为 false: 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 的特殊化存在,但任何将其用作 a 的尝试都是错误Hash 的。— <em>结束注释]

因此,以下 Minimal Reproducible Example 不应编译,因为它尝试默认构造 的禁用特化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_views 启用。

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

4

1 回答 1

4

你似乎是正确的。Libc++ 正确禁用了您的散列std::basic_string,但不禁用std::basic_string_view.

稍后:为 LLVM 9.0 修复

于 2019-06-27T13:54:18.057 回答