libc++ 是否为太多 basic_string_view 提供散列专业化?
Is libc++ providing hash specialization for too many basic_string_view's?
// ...
// [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
已禁用其 hash
es。
根据 [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
// ... // [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
已禁用其 hash
es。
根据 [unord.hash]/2:
[...] For any type
Key
for which neither the library nor the user provides an explicit or partial specialization of the class templatehash
,hash<Key>
is disabled.
根据 [unord.hash]/4:
If
H
is a disabled specialization ofhash
, these values are false:is_default_constructible_v<H>
,is_copy_constructible_v<H>
,is_move_constructible_v<H>
,is_copy_assignable_v<H>
, andis_move_assignable_v<H>
. Disabled specializations ofhash
are not function object types. [ Note: This means that the specialization of hash exists, but any attempts to use it as aHash
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