The test cover constructors introduced in [PATCH v2] libstdc++-v3: Implement missing allocator-aware constructors for unordered containers, so I will merge that after.
On Fri, Apr 18, 2025 at 5:18 PM Jonathan Wakely <jwakely....@gmail.com> wrote: > > > On Fri, 18 Apr 2025, 12:55 Tomasz Kamiński, <tkami...@redhat.com> wrote: > >> This implements part of LWG4223 that adjust the deduction guides for maps >> types >> (map, unordered_map, flat_map and non-unique equivalent) from "range", >> such that >> referience and cv qualification are stripped from the element of the >> pair-like >> value_type. >> >> In combination with r15-8296-gd50171bc07006d, the LWG4223 is fully >> implemented now. >> >> libstdc++-v3/ChangeLog: >> >> * include/bits/ranges_base.h (__detail::__range_key_type): >> Replace remove_const_t with remove_cvref_t. >> (__detail::__range_mapped_type): Apply remove_cvref_t. >> * include/bits/stl_iterator.h: (__detail::__iter_key_t): >> Replace remove_const_t with __remove_cvref_t. >> (__detail::__iter_val_t): Apply __remove_cvref_t. >> * testsuite/23_containers/flat_map/1.cc: New tests. >> * testsuite/23_containers/flat_multimap/1.cc: New tests. >> * testsuite/23_containers/map/cons/deduction.cc: New tests. >> * testsuite/23_containers/map/cons/from_range.cc: New tests. >> * testsuite/23_containers/multimap/cons/deduction.cc: New tests. >> * testsuite/23_containers/multimap/cons/from_range.cc: New tests. >> * testsuite/23_containers/unordered_map/cons/deduction.cc: New >> tests. >> * testsuite/23_containers/unordered_map/cons/from_range.cc: New >> tests. >> * testsuite/23_containers/unordered_multimap/cons/deduction.cc: >> New tests. >> * testsuite/23_containers/unordered_multimap/cons/from_range.cc: >> New tests. >> --- >> Desipite there being some discussion about this on reflector, I think we >> should go ahead with this, to avoid creating maps of references/const >> types. >> As we are at the begining of development of 16, this seems like a good >> time >> to do it. >> OK for trunk? >> > > OK for trunk. > > > >> >> libstdc++-v3/include/bits/ranges_base.h | 4 +- >> libstdc++-v3/include/bits/stl_iterator.h | 11 +-- >> .../testsuite/23_containers/flat_map/1.cc | 21 +++--- >> .../23_containers/flat_multimap/1.cc | 21 +++--- >> .../23_containers/map/cons/deduction.cc | 46 +++++++++++++ >> .../23_containers/map/cons/from_range.cc | 8 +-- >> .../23_containers/multimap/cons/deduction.cc | 46 +++++++++++++ >> .../23_containers/multimap/cons/from_range.cc | 8 +-- >> .../unordered_map/cons/deduction.cc | 69 +++++++++++++++++++ >> .../unordered_map/cons/from_range.cc | 10 ++- >> .../unordered_multimap/cons/deduction.cc | 69 +++++++++++++++++++ >> .../unordered_multimap/cons/from_range.cc | 10 +-- >> 12 files changed, 279 insertions(+), 44 deletions(-) >> >> diff --git a/libstdc++-v3/include/bits/ranges_base.h >> b/libstdc++-v3/include/bits/ranges_base.h >> index 488907da446..dde16498856 100644 >> --- a/libstdc++-v3/include/bits/ranges_base.h >> +++ b/libstdc++-v3/include/bits/ranges_base.h >> @@ -1103,11 +1103,11 @@ namespace __detail >> // 4223. Deduction guides for maps are mishandling tuples and >> references >> template<ranges::input_range _Range> >> using __range_key_type >> - = remove_const_t<tuple_element_t<0, >> ranges::range_value_t<_Range>>>; >> + = remove_cvref_t<tuple_element_t<0, >> ranges::range_value_t<_Range>>>; >> >> template<ranges::input_range _Range> >> using __range_mapped_type >> - = tuple_element_t<1, ranges::range_value_t<_Range>>; >> + = remove_cvref_t<tuple_element_t<1, >> ranges::range_value_t<_Range>>>; >> >> // The allocator's value_type for map-like containers. >> template<ranges::input_range _Range> >> diff --git a/libstdc++-v3/include/bits/stl_iterator.h >> b/libstdc++-v3/include/bits/stl_iterator.h >> index 9203a66b2ff..bed72955d0c 100644 >> --- a/libstdc++-v3/include/bits/stl_iterator.h >> +++ b/libstdc++-v3/include/bits/stl_iterator.h >> @@ -3086,8 +3086,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION >> #if __cpp_deduction_guides >= 201606 >> // These helper traits are used for deduction guides >> // of associative containers. >> + >> + // _GLIBCXX_RESOLVE_LIB_DEFECTS >> + // 4223. Deduction guides for maps are mishandling tuples and >> references >> template<typename _InputIterator> >> - using __iter_key_t = remove_const_t< >> + using __iter_key_t = __remove_cvref_t< >> #ifdef __glibcxx_tuple_like // >= C++23 >> tuple_element_t<0, typename >> iterator_traits<_InputIterator>::value_type>>; >> #else >> @@ -3095,11 +3098,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION >> #endif >> >> template<typename _InputIterator> >> - using __iter_val_t >> + using __iter_val_t = __remove_cvref_t< >> #ifdef __glibcxx_tuple_like // >= C++23 >> - = tuple_element_t<1, typename >> iterator_traits<_InputIterator>::value_type>; >> + tuple_element_t<1, typename >> iterator_traits<_InputIterator>::value_type>>; >> #else >> - = typename >> iterator_traits<_InputIterator>::value_type::second_type; >> + typename iterator_traits<_InputIterator>::value_type::second_type>; >> #endif >> >> template<typename _T1, typename _T2> >> diff --git a/libstdc++-v3/testsuite/23_containers/flat_map/1.cc >> b/libstdc++-v3/testsuite/23_containers/flat_map/1.cc >> index d9d88c4df6e..6105a2865c9 100644 >> --- a/libstdc++-v3/testsuite/23_containers/flat_map/1.cc >> +++ b/libstdc++-v3/testsuite/23_containers/flat_map/1.cc >> @@ -55,16 +55,17 @@ test_deduction_guide() >> std::vector<long, __gnu_test::SimpleAllocator<long>>, >> std::vector<float, >> __gnu_test::SimpleAllocator<float>>>>); >> >> - // LWG4223: deduces flat_map<long, float const>, which in turn >> instantiates >> - // std::vector<cosnt float> that is ill-formed. >> - // __gnu_test::test_input_range<std::pair<const long, const float>> >> r2(0, 0); >> - // std::flat_map it5(r2.begin(), r2.begin()); >> - // std::flat_map fr5(std::from_range, r2); >> - >> - // LWG4223: deduces flat_map<const long&, float&> >> - //__gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, >> 0); >> - // std::flat_map it6(r3.begin(), r3.begin()); >> - // std::flat_map fr6(std::from_range, r3); >> + __gnu_test::test_input_range<std::pair<const long, const float>> r2(0, >> 0); >> + std::flat_map it5(r2.begin(), r2.begin()); >> + static_assert(std::is_same_v<decltype(it5), std::flat_map<long, >> float>>); >> + std::flat_map fr5(std::from_range, r2); >> + static_assert(std::is_same_v<decltype(fr5), std::flat_map<long, >> float>>); >> + >> + __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0); >> + std::flat_map it6(r3.begin(), r3.begin()); >> + static_assert(std::is_same_v<decltype(it6), std::flat_map<long, >> float>>); >> + std::flat_map fr6(std::from_range, r3); >> + static_assert(std::is_same_v<decltype(fr6), std::flat_map<long, >> float>>); >> >> __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0); >> std::flat_map it7(r4.begin(), r4.begin()); >> diff --git a/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc >> b/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc >> index ff180bf1bdf..ac8b0e0d7d9 100644 >> --- a/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc >> +++ b/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc >> @@ -53,16 +53,17 @@ test_deduction_guide() >> std::vector<long, __gnu_test::SimpleAllocator<long>>, >> std::vector<float, >> __gnu_test::SimpleAllocator<float>>>>); >> >> - // LWG4223: deduces flat_multimap<long, float const>, which in turn >> instantiates >> - // std::vector<cosnt float> that is ill-formed. >> - // __gnu_test::test_input_range<std::pair<const long, const float>> >> r2(0, 0); >> - // std::flat_multimap it5(r2.begin(), r2.begin()); >> - // std::flat_multimap fr5(std::from_range, r2); >> - >> - // LWG4223: deduces flat_multimap<const long&, float&> >> - //__gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, >> 0); >> - // std::flat_multimap it6(r3.begin(), r3.begin()); >> - // std::flat_multimap fr6(std::from_range, r3); >> + __gnu_test::test_input_range<std::pair<const long, const float>> r2(0, >> 0); >> + std::flat_multimap it5(r2.begin(), r2.begin()); >> + static_assert(std::is_same_v<decltype(it5), std::flat_multimap<long, >> float>>); >> + std::flat_multimap fr5(std::from_range, r2); >> + static_assert(std::is_same_v<decltype(fr5), std::flat_multimap<long, >> float>>); >> + >> + __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0); >> + std::flat_multimap it6(r3.begin(), r3.begin()); >> + static_assert(std::is_same_v<decltype(it6), std::flat_multimap<long, >> float>>); >> + std::flat_multimap fr6(std::from_range, r3); >> + static_assert(std::is_same_v<decltype(fr6), std::flat_multimap<long, >> float>>); >> >> __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0); >> std::flat_multimap it7(r4.begin(), r4.begin()); >> diff --git a/libstdc++-v3/testsuite/23_containers/map/cons/deduction.cc >> b/libstdc++-v3/testsuite/23_containers/map/cons/deduction.cc >> index f8e6e6e8b99..194bff5bf78 100644 >> --- a/libstdc++-v3/testsuite/23_containers/map/cons/deduction.cc >> +++ b/libstdc++-v3/testsuite/23_containers/map/cons/deduction.cc >> @@ -258,3 +258,49 @@ test_p1518r2() >> std::map s2(std::move(m), p); >> check_type<Map>(s2); >> } >> + >> +struct MyPred >> +{ >> + template<typename T, typename U> >> + bool operator()(T const&, U const&) const; >> +}; >> + >> +template<typename K, typename V> >> +constexpr bool test_lwg4223() >> +{ >> + using KD = std::remove_cvref_t<K>; >> + using VD = std::remove_cvref_t<V>; >> + using Alloc = __gnu_test::SimpleAllocator<std::pair<const KD, VD>>; >> + >> + std::initializer_list<std::pair<K, V>> il = {}; >> + Alloc a; >> + MyPred p; >> + >> + // The remove_cvref_t is not applied here. >> + // static_assert(std::is_same_v< >> + // decltype(std::map(il)), >> + // std::map<KD, VD>>); >> + >> + static_assert(std::is_same_v< >> + decltype(std::map(il.begin(), il.end())), >> + std::map<KD, VD>>); >> + >> + static_assert(std::is_same_v< >> + decltype(std::map(il.begin(), il.end(), p)), >> + std::map<KD, VD, MyPred>>); >> + >> + static_assert(std::is_same_v< >> + decltype(std::map(il.begin(), il.end(), a)), >> + std::map<KD, VD, std::less<KD>, Alloc>>); >> + >> + static_assert(std::is_same_v< >> + decltype(std::map(il.begin(), il.end(), p, a)), >> + std::map<KD, VD, MyPred, Alloc>>); >> + >> + return true; >> +} >> + >> +static_assert(test_lwg4223<const int, const float>()); >> +static_assert(test_lwg4223<int&, float&>()); >> +static_assert(test_lwg4223<int&&, float&&>()); >> +static_assert(test_lwg4223<const int&, const float&>()); >> diff --git a/libstdc++-v3/testsuite/23_containers/map/cons/from_range.cc >> b/libstdc++-v3/testsuite/23_containers/map/cons/from_range.cc >> index 9935f44aa0f..3a9fede0434 100644 >> --- a/libstdc++-v3/testsuite/23_containers/map/cons/from_range.cc >> +++ b/libstdc++-v3/testsuite/23_containers/map/cons/from_range.cc >> @@ -43,11 +43,11 @@ test_deduction_guide() >> >> __gnu_test::test_input_range<std::pair<const long, const float>> r2(0, >> 0); >> std::map m5(std::from_range, r2); >> - static_assert(std::is_same_v<decltype(m5), std::map<long, const >> float>>); >> + static_assert(std::is_same_v<decltype(m5), std::map<long, float>>); >> >> - // LWG4223: deduces map<const long&, float&> >> - //__gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, >> 0); >> - // std::map m6(std::from_range, r3); >> + __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0); >> + std::map m6(std::from_range, r3); >> + static_assert(std::is_same_v<decltype(m6), std::map<long, float>>); >> >> __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0); >> std::map m7(std::from_range, r4); >> diff --git >> a/libstdc++-v3/testsuite/23_containers/multimap/cons/deduction.cc >> b/libstdc++-v3/testsuite/23_containers/multimap/cons/deduction.cc >> index f0699e2eefc..84754f3f561 100644 >> --- a/libstdc++-v3/testsuite/23_containers/multimap/cons/deduction.cc >> +++ b/libstdc++-v3/testsuite/23_containers/multimap/cons/deduction.cc >> @@ -210,3 +210,49 @@ test_p1518r2() >> std::multimap s2(std::move(m), p); >> check_type<MMap>(s2); >> } >> + >> +struct MyPred >> +{ >> + template<typename T, typename U> >> + bool operator()(T const&, U const&) const; >> +}; >> + >> +template<typename K, typename V> >> +constexpr bool test_lwg4223() >> +{ >> + using KD = std::remove_cvref_t<K>; >> + using VD = std::remove_cvref_t<V>; >> + using Alloc = __gnu_test::SimpleAllocator<std::pair<const KD, VD>>; >> + >> + std::initializer_list<std::pair<K, V>> il = {}; >> + Alloc a; >> + MyPred p; >> + >> + // The remove_cvref_t is not applied here. >> + // static_assert(std::is_same_v< >> + // decltype(std::multimap(il)), >> + // std::multimap<KD, VD>>); >> + >> + static_assert(std::is_same_v< >> + decltype(std::multimap(il.begin(), il.end())), >> + std::multimap<KD, VD>>); >> + >> + static_assert(std::is_same_v< >> + decltype(std::multimap(il.begin(), il.end(), p)), >> + std::multimap<KD, VD, MyPred>>); >> + >> + static_assert(std::is_same_v< >> + decltype(std::multimap(il.begin(), il.end(), a)), >> + std::multimap<KD, VD, std::less<KD>, Alloc>>); >> + >> + static_assert(std::is_same_v< >> + decltype(std::multimap(il.begin(), il.end(), p, a)), >> + std::multimap<KD, VD, MyPred, Alloc>>); >> + >> + return true; >> +} >> + >> +static_assert(test_lwg4223<const int, const float>()); >> +static_assert(test_lwg4223<int&, float&>()); >> +static_assert(test_lwg4223<int&&, float&&>()); >> +static_assert(test_lwg4223<const int&, const float&>()); >> diff --git >> a/libstdc++-v3/testsuite/23_containers/multimap/cons/from_range.cc >> b/libstdc++-v3/testsuite/23_containers/multimap/cons/from_range.cc >> index 4a8ea9fec7d..5907bab9878 100644 >> --- a/libstdc++-v3/testsuite/23_containers/multimap/cons/from_range.cc >> +++ b/libstdc++-v3/testsuite/23_containers/multimap/cons/from_range.cc >> @@ -43,11 +43,11 @@ test_deduction_guide() >> >> __gnu_test::test_input_range<std::pair<const long, const float>> r2(0, >> 0); >> std::multimap m5(std::from_range, r2); >> - static_assert(std::is_same_v<decltype(m5), std::multimap<long, const >> float>>); >> + static_assert(std::is_same_v<decltype(m5), std::multimap<long, >> float>>); >> >> - // LWG4223: deduces multimap<const long&, float&> >> - //__gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, >> 0); >> - // std::multimap m6(std::from_range, r3); >> + __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0); >> + std::multimap m6(std::from_range, r3); >> + static_assert(std::is_same_v<decltype(m6), std::multimap<long, >> float>>); >> >> __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0); >> std::multimap m7(std::from_range, r4); >> diff --git >> a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/deduction.cc >> b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/deduction.cc >> index 8b69af896a2..e806de2045c 100644 >> --- a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/deduction.cc >> +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/deduction.cc >> @@ -162,3 +162,72 @@ test_p1518r2() >> std::unordered_map s2(std::move(m), p); >> check_type<UMap>(s2); >> } >> + >> +struct MyHash >> +{ >> + template<typename T> >> + std::size_t operator()(T const&) const; >> +}; >> + >> +struct MyPred >> +{ >> + template<typename T, typename U> >> + bool operator()(T const&, U const&) const; >> +}; >> + >> +template<typename K, typename V> >> +constexpr bool test_lwg4223() >> +{ >> + using KD = std::remove_cvref_t<K>; >> + using VD = std::remove_cvref_t<V>; >> + using Alloc = __gnu_test::SimpleAllocator<std::pair<const KD, VD>>; >> + >> + std::initializer_list<std::pair<K, V>> il = {}; >> + Alloc a; >> + MyHash h; >> + MyPred p; >> + >> + // The remove_cvref_t is not applied here. >> + // static_assert(std::is_same_v< >> + // decltype(std::unordered_map(il)), >> + // std::unordered_map<KD, VD>>); >> + >> + static_assert(std::is_same_v< >> + decltype(std::unordered_map(il.begin(), il.end())), >> + std::unordered_map<KD, VD>>); >> + >> + static_assert(std::is_same_v< >> + decltype(std::unordered_map(il.begin(), il.end(), 0)), >> + std::unordered_map<KD, VD>>); >> + >> + static_assert(std::is_same_v< >> + decltype(std::unordered_map(il.begin(), il.end(), 0, h)), >> + std::unordered_map<KD, VD, MyHash>>); >> + >> + static_assert(std::is_same_v< >> + decltype(std::unordered_map(il.begin(), il.end(), 0, h, p)), >> + std::unordered_map<KD, VD, MyHash, MyPred>>); >> + >> + static_assert(std::is_same_v< >> + decltype(std::unordered_map(il.begin(), il.end(), a)), >> + std::unordered_map<KD, VD, std::hash<KD>, std::equal_to<KD>, >> Alloc>>); >> + >> + static_assert(std::is_same_v< >> + decltype(std::unordered_map(il.begin(), il.end(), 0, a)), >> + std::unordered_map<KD, VD, std::hash<KD>, std::equal_to<KD>, >> Alloc>>); >> + >> + static_assert(std::is_same_v< >> + decltype(std::unordered_map(il.begin(), il.end(), 0, h, a)), >> + std::unordered_map<KD, VD, MyHash, std::equal_to<KD>, Alloc>>); >> + >> + static_assert(std::is_same_v< >> + decltype(std::unordered_map(il.begin(), il.end(), 0, h, p, a)), >> + std::unordered_map<KD, VD, MyHash, MyPred, Alloc>>); >> + >> + return true; >> +} >> + >> +static_assert(test_lwg4223<const int, const float>()); >> +static_assert(test_lwg4223<int&, float&>()); >> +static_assert(test_lwg4223<int&&, float&&>()); >> +static_assert(test_lwg4223<const int&, const float&>()); >> diff --git >> a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/from_range.cc >> b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/from_range.cc >> index 36efc2de5a3..04479a5e54d 100644 >> --- >> a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/from_range.cc >> +++ >> b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/from_range.cc >> @@ -78,13 +78,11 @@ test_deduction_guide() >> >> __gnu_test::test_input_range<std::pair<const long, const float>> r2(0, >> 0); >> std::unordered_map m9(std::from_range, r2); >> - static_assert(std::is_same_v< >> - decltype(m9), >> - std::unordered_map<long, const float>>); >> + static_assert(std::is_same_v<decltype(m9), std::unordered_map<long, >> float>>); >> >> - // LWG4223: deduces map<const long&, float&> >> - // __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, >> 0); >> - // std::unordered_map m10(std::from_range, r3); >> + __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0); >> + std::unordered_map m10(std::from_range, r3); >> + static_assert(std::is_same_v<decltype(m10), std::unordered_map<long, >> float>>); >> >> __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0); >> std::unordered_map m11(std::from_range, r4); >> diff --git >> a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/deduction.cc >> b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/deduction.cc >> index e7e535b527a..786e5030bb2 100644 >> --- >> a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/deduction.cc >> +++ >> b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/deduction.cc >> @@ -171,3 +171,72 @@ test_p1518r2() >> std::unordered_multimap s2(std::move(m), p); >> check_type<UMMap>(s2); >> } >> + >> +struct MyHash >> +{ >> + template<typename T> >> + std::size_t operator()(T const&) const; >> +}; >> + >> +struct MyPred >> +{ >> + template<typename T, typename U> >> + bool operator()(T const&, U const&) const; >> +}; >> + >> +template<typename K, typename V> >> +constexpr bool test_lwg4223() >> +{ >> + using KD = std::remove_cvref_t<K>; >> + using VD = std::remove_cvref_t<V>; >> + using Alloc = __gnu_test::SimpleAllocator<std::pair<const KD, VD>>; >> + >> + std::initializer_list<std::pair<K, V>> il = {}; >> + Alloc a; >> + MyHash h; >> + MyPred p; >> + >> + // The remove_cvref_t is not applied here. >> + // static_assert(std::is_same_v< >> + // decltype(std::unordered_multimap(il)), >> + // std::unordered_multimap<KD, VD>>); >> + >> + static_assert(std::is_same_v< >> + decltype(std::unordered_multimap(il.begin(), il.end())), >> + std::unordered_multimap<KD, VD>>); >> + >> + static_assert(std::is_same_v< >> + decltype(std::unordered_multimap(il.begin(), il.end(), 0)), >> + std::unordered_multimap<KD, VD>>); >> + >> + static_assert(std::is_same_v< >> + decltype(std::unordered_multimap(il.begin(), il.end(), 0, h)), >> + std::unordered_multimap<KD, VD, MyHash>>); >> + >> + static_assert(std::is_same_v< >> + decltype(std::unordered_multimap(il.begin(), il.end(), 0, h, p)), >> + std::unordered_multimap<KD, VD, MyHash, MyPred>>); >> + >> + static_assert(std::is_same_v< >> + decltype(std::unordered_multimap(il.begin(), il.end(), a)), >> + std::unordered_multimap<KD, VD, std::hash<KD>, std::equal_to<KD>, >> Alloc>>); >> + >> + static_assert(std::is_same_v< >> + decltype(std::unordered_multimap(il.begin(), il.end(), 0, a)), >> + std::unordered_multimap<KD, VD, std::hash<KD>, std::equal_to<KD>, >> Alloc>>); >> + >> + static_assert(std::is_same_v< >> + decltype(std::unordered_multimap(il.begin(), il.end(), 0, h, a)), >> + std::unordered_multimap<KD, VD, MyHash, std::equal_to<KD>, Alloc>>); >> + >> + static_assert(std::is_same_v< >> + decltype(std::unordered_multimap(il.begin(), il.end(), 0, h, p, a)), >> + std::unordered_multimap<KD, VD, MyHash, MyPred, Alloc>>); >> + >> + return true; >> +} >> + >> +static_assert(test_lwg4223<const int, const float>()); >> +static_assert(test_lwg4223<int&, float&>()); >> +static_assert(test_lwg4223<int&&, float&&>()); >> +static_assert(test_lwg4223<const int&, const float&>()); >> diff --git >> a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/from_range.cc >> b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/from_range.cc >> index b551df49f3e..4567bd8aa91 100644 >> --- >> a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/from_range.cc >> +++ >> b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/from_range.cc >> @@ -86,11 +86,13 @@ test_deduction_guide() >> std::unordered_multimap m9(std::from_range, r2); >> static_assert(std::is_same_v< >> decltype(m9), >> - std::unordered_multimap<long, const float>>); >> + std::unordered_multimap<long, float>>); >> >> - // LWG4223: deduces map<const long&, float&> >> - // __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, >> 0); >> - // std::unordered_multimap m10(std::from_range, r3); >> + __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0); >> + std::unordered_multimap m10(std::from_range, r3); >> + static_assert(std::is_same_v< >> + decltype(m10), >> + std::unordered_multimap<long, float>>); >> >> __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0); >> std::unordered_multimap m11(std::from_range, r4); >> -- >> 2.49.0 >> >>