Title
Hashability shouldn't depend on basic_string's allocator
Status
c++23
Section
[basic.string.hash]
Submitter
Casey Carter

Created on 2022-05-26.00:00:00 last changed 13 months ago

Messages

Date: 2022-07-25.20:32:58

Proposed resolution:

This wording is relative to N4910.

  1. Modify [string.syn], header <string> synopsis, as indicated:

    […]
    
    // [basic.string.hash], hash support
    template<class T> struct hash;
    template<> struct hash<string>;
    template<> struct hash<u8string>;
    template<> struct hash<u16string>;
    template<> struct hash<u32string>;
    template<> struct hash<wstring>;
    template<> struct hash<pmr::string>;
    template<> struct hash<pmr::u8string>;
    template<> struct hash<pmr::u16string>;
    template<> struct hash<pmr::u32string>;
    template<> struct hash<pmr::wstring>;
    template<class A> struct hash<basic_string<char, char_traits<char>, A>>;
    template<class A> struct hash<basic_string<char8_t, char_traits<char8_t>, A>>;
    template<class A> struct hash<basic_string<char16_t, char_traits<char16_t>, A>>;
    template<class A> struct hash<basic_string<char32_t, char_traits<char32_t>, A>>;
    template<class A> struct hash<basic_string<wchar_t, char_traits<wchar_t>, A>>;
    
    […]
    
  2. Modify [basic.string.hash] as indicated:

    template<> struct hash<string>;
    template<> struct hash<u8string>;
    template<> struct hash<u16string>;
    template<> struct hash<u32string>;
    template<> struct hash<wstring>;
    template<> struct hash<pmr::string>;
    template<> struct hash<pmr::u8string>;
    template<> struct hash<pmr::u16string>;
    template<> struct hash<pmr::u32string>;
    template<> struct hash<pmr::wstring>;
    template<class A> struct hash<basic_string<char, char_traits<char>, A>>;
    template<class A> struct hash<basic_string<char8_t, char_traits<char8_t>, A>>;
    template<class A> struct hash<basic_string<char16_t, char_traits<char16_t>, A>>;
    template<class A> struct hash<basic_string<char32_t, char_traits<char32_t>, A>>;
    template<class A> struct hash<basic_string<wchar_t, char_traits<wchar_t>, A>>;
    

    -1- If S is one of these string types, SV is the corresponding string view type, and s is an object of type S, then hash<S>()(s) == hash<SV>()(SV(s))

Date: 2022-07-25.00:00:00

[ 2022-07-25 Approved at July 2022 virtual plenary. Status changed: Ready → WP. ]

Date: 2022-07-15.00:00:00

[ 2022-07-15; LWG telecon: move to Ready ]

Date: 2022-06-15.00:00:00

[ 2022-06-21; Reflector poll ]

Set status to Tentatively Ready after seven votes in favour during reflector poll.

Date: 2022-05-26.00:00:00

[basic.string.hash] says:

template<> struct hash<string>;
template<> struct hash<u8string>;
template<> struct hash<u16string>;
template<> struct hash<u32string>;
template<> struct hash<wstring>;
template<> struct hash<pmr::string>;
template<> struct hash<pmr::u8string>;
template<> struct hash<pmr::u16string>;
template<> struct hash<pmr::u32string>;
template<> struct hash<pmr::wstring>;

-1- If S is one of these string types, SV is the corresponding string view type, and s is an object of type S, then hash<S>()(s) == hash<SV>()(SV(s))

Despite that the hash value of a basic_string object is equivalent to the hash value of a corresponding basic_string_view object, which has no allocator, the capability to hash a basic_string depends on its allocator. All of the enabled specializations have specific allocators, which fact becomes more clear if we expand the type aliases:

template<> struct hash<basic_string<char, char_traits<char>, allocator<char>>;
template<> struct hash<basic_string<char8_t, char_traits<char8_t>, allocator<char8_t>>;

template<> struct hash<basic_string<char16_t, char_traits<char16_t>, allocator<char16_t>>;

template<> struct hash<basic_string<char32_t, char_traits<char32_t>, allocator<char32_t>>;

template<> struct hash<basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t>>;

template<> struct hash<basic_string<char, char_traits<char>, pmr::polymorphic_allocator<char>>;
template<> struct hash<basic_string<char8_t, char_traits<char8_t>, pmr::polymorphic_allocator<char8_t>>;

template<> struct hash<basic_string<char16_t, char_traits<char16_t>, pmr::polymorphic_allocator<char16_t>>;

template<> struct hash<basic_string<char32_t, char_traits<char32_t>, pmr::polymorphic_allocator<char32_t>>;

template<> struct hash<basic_string<wchar_t, char_traits<wchar_t>, pmr::polymorphic_allocator<wchar_t>>;

If the hash value doesn't depend on the allocator type, why should we care about the allocator type? I posit that we should not, and that these ten explicit specializations should be replaced by 5 partial specializations that enable hashing basic_string specializations using these combinations of character type and traits type with any allocator type.

History
Date User Action Args
2023-11-22 15:47:43adminsetstatus: wp -> c++23
2022-07-25 20:32:58adminsetmessages: + msg12647
2022-07-25 20:32:58adminsetstatus: ready -> wp
2022-07-25 20:28:19adminsetmessages: + msg12621
2022-06-21 11:47:28adminsetmessages: + msg12517
2022-06-21 11:47:28adminsetstatus: new -> ready
2022-05-29 09:50:57adminsetmessages: + msg12482
2022-05-26 00:00:00admincreate