L. F.
L. F.

Reputation: 20629

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

Per [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>;

// ...

Only for the four "common" basic_string_views are specializations of hash enabled. The other basic_string_views have their hashes disabled.

Per [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.

Per [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 ]

Therefore, the following Minimal Reproducible Example should not compile because it attempts to default construct a disabled specialization of 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;
}

However, this compiles 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());
    }
};

So libc++ actually enables hash for all basic_string_views.

Therefore, I conclude that this is a bug in libc++. Is my analysis correct?

Upvotes: 1

Views: 291

Answers (1)

Marshall Clow
Marshall Clow

Reputation: 16690

You appear to be correct. Libc++ correctly disables your hash for std::basic_string, but not for std::basic_string_view.

Later: Fixed for LLVM 9.0

Upvotes: 4

Related Questions