From d50171bc07006dfb56cae487d72913e5d2567716 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tomasz=20Kami=C5=84ski?= Date: Wed, 19 Mar 2025 11:42:50 +0100 Subject: [PATCH] libstdc++: Support maps deduction from_range of tuples. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This implements part of LWG4223 that enables deduction for maps types (map, unordered_map, flat_map and non-unique equivalent) from (from_range, rg, ...) arguments, where rg is range of tuple or other pair-like. libstdc++-v3/ChangeLog: * include/bits/ranges_base.h (__detail::__range_key_type): Replace RV::first_type with tuple_element_t<0, RV>. (__detail::__range_mapped_type) Replace RV::second_type with tuple_element_t<1, RV>. * testsuite/23_containers/flat_map/1.cc: New tests. * testsuite/23_containers/flat_multimap/1.cc: New tests. * testsuite/23_containers/map/cons/from_range.cc: New tests. * testsuite/23_containers/multimap/cons/from_range.cc: New tests. * testsuite/23_containers/unordered_map/cons/from_range.cc: New tests. * testsuite/23_containers/unordered_multimap/cons/from_range.cc: New tests. Reviewed-by: Jonathan Wakely Signed-off-by: Tomasz Kamiński --- libstdc++-v3/include/bits/ranges_base.h | 10 ++- .../testsuite/23_containers/flat_map/1.cc | 61 +++++++++++++++++ .../23_containers/flat_multimap/1.cc | 65 +++++++++++++++++++ .../23_containers/map/cons/from_range.cc | 8 ++- .../23_containers/multimap/cons/from_range.cc | 8 ++- .../unordered_map/cons/from_range.cc | 8 ++- .../unordered_multimap/cons/from_range.cc | 12 +++- 7 files changed, 158 insertions(+), 14 deletions(-) diff --git a/libstdc++-v3/include/bits/ranges_base.h b/libstdc++-v3/include/bits/ranges_base.h index c9687c256e9..13bfbb3795b 100644 --- a/libstdc++-v3/include/bits/ranges_base.h +++ b/libstdc++-v3/include/bits/ranges_base.h @@ -41,6 +41,10 @@ #include #include +#if __glibcxx_ranges_to_container // C++ >= 23 +# include // for tuple_element_t +#endif + #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" // __int128 @@ -1093,13 +1097,15 @@ namespace __detail = ranges::input_range<_Rg> && convertible_to, _Tp>; + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4223. Deduction guides for maps are mishandling tuples and references template using __range_key_type - = remove_const_t::first_type>; + = remove_const_t>>; template using __range_mapped_type - = typename ranges::range_value_t<_Range>::second_type; + = tuple_element_t<1, ranges::range_value_t<_Range>>; // The allocator's value_type for map-like containers. template diff --git a/libstdc++-v3/testsuite/23_containers/flat_map/1.cc b/libstdc++-v3/testsuite/23_containers/flat_map/1.cc index 00254dc2ee6..d9d88c4df6e 100644 --- a/libstdc++-v3/testsuite/23_containers/flat_map/1.cc +++ b/libstdc++-v3/testsuite/23_containers/flat_map/1.cc @@ -11,6 +11,67 @@ #include #include #include +#include +#include + +struct Gt { + template + bool operator()(T const& l, U const & r) const + { return l > r; } +}; + +void +test_deduction_guide() +{ + __gnu_test::test_input_range> r(0, 0); + std::flat_map it1(r.begin(), r.begin()); + static_assert(std::is_same_v>); + std::flat_map fr1(std::from_range, r); + static_assert(std::is_same_v>); + + Gt cmp; + std::flat_map it2(r.begin(), r.begin(), cmp); + static_assert(std::is_same_v>); + std::flat_map fr2(std::from_range, r, cmp); + static_assert(std::is_same_v>); + + using Alloc = __gnu_test::SimpleAllocator>; + Alloc alloc; + // No matching deduction guide + // std::flat_map it3(r.begin(), r.begin(), alloc); + std::flat_map fr3(std::from_range, r, alloc); + static_assert(std::is_same_v< + decltype(fr3), + std::flat_map, + std::vector>, + std::vector>>>); + + // No matching deduction guide + // std::flat_map it4(r.begin(), r.begin(), cmp, alloc); + std::flat_map fr4(std::from_range, r, cmp, alloc); + static_assert(std::is_same_v< + decltype(fr4), + std::flat_map>, + std::vector>>>); + + // LWG4223: deduces flat_map, which in turn instantiates + // std::vector that is ill-formed. + // __gnu_test::test_input_range> r2(0, 0); + // std::flat_map it5(r2.begin(), r2.begin()); + // std::flat_map fr5(std::from_range, r2); + + // LWG4223: deduces flat_map + //__gnu_test::test_input_range> r3(0, 0); + // std::flat_map it6(r3.begin(), r3.begin()); + // std::flat_map fr6(std::from_range, r3); + + __gnu_test::test_input_range> r4(0, 0); + std::flat_map it7(r4.begin(), r4.begin()); + static_assert(std::is_same_v>); + std::flat_map fr7(std::from_range, r4); + static_assert(std::is_same_v>); +} template class KeyContainer, template class MappedContainer> void diff --git a/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc b/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc index 38650a81bcf..ff180bf1bdf 100644 --- a/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc +++ b/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc @@ -5,6 +5,71 @@ #include #include #include +#include +#include + +struct Gt { + template + bool operator()(T const& l, U const & r) const + { return l > r; } +}; + +void +test_deduction_guide() +{ + __gnu_test::test_input_range> r(0, 0); + std::flat_multimap it1(r.begin(), r.begin()); + static_assert(std::is_same_v>); + std::flat_multimap fr1(std::from_range, r); + static_assert(std::is_same_v>); + + Gt cmp; + std::flat_multimap it2(r.begin(), r.begin(), cmp); + static_assert(std::is_same_v< + decltype(it2), + std::flat_multimap>); + std::flat_multimap fr2(std::from_range, r, cmp); + static_assert(std::is_same_v< + decltype(fr2), + std::flat_multimap>); + + using Alloc = __gnu_test::SimpleAllocator>; + Alloc alloc; + // No matching deduction guide + // std::flat_multimap it3(r.begin(), r.begin(), alloc); + std::flat_multimap fr3(std::from_range, r, alloc); + static_assert(std::is_same_v< + decltype(fr3), + std::flat_multimap, + std::vector>, + std::vector>>>); + + // No matching deduction guide + // std::flat_multimap it4(r.begin(), r.begin(), cmp, alloc); + std::flat_multimap fr4(std::from_range, r, cmp, alloc); + static_assert(std::is_same_v< + decltype(fr4), + std::flat_multimap>, + std::vector>>>); + + // LWG4223: deduces flat_multimap, which in turn instantiates + // std::vector that is ill-formed. + // __gnu_test::test_input_range> r2(0, 0); + // std::flat_multimap it5(r2.begin(), r2.begin()); + // std::flat_multimap fr5(std::from_range, r2); + + // LWG4223: deduces flat_multimap + //__gnu_test::test_input_range> r3(0, 0); + // std::flat_multimap it6(r3.begin(), r3.begin()); + // std::flat_multimap fr6(std::from_range, r3); + + __gnu_test::test_input_range> r4(0, 0); + std::flat_multimap it7(r4.begin(), r4.begin()); + static_assert(std::is_same_v>); + std::flat_multimap fr7(std::from_range, r4); + static_assert(std::is_same_v>); +} template class KeyContainer, template class MappedContainer> void 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 01e426fde3d..c740471f2da 100644 --- a/libstdc++-v3/testsuite/23_containers/map/cons/from_range.cc +++ b/libstdc++-v3/testsuite/23_containers/map/cons/from_range.cc @@ -44,9 +44,11 @@ test_deduction_guide() //__gnu_test::test_input_range> r3(0, 0); // std::map m6(std::from_range, r3); - // LWG4223: no deduction guide - // __gnu_test::test_input_range> r4(0, 0); - // std::map m7(std::from_range, r4); + __gnu_test::test_input_range> r4(0, 0); + std::map m7(std::from_range, r4); + static_assert(std::is_same_v>); + std::map it7(r4.begin(), r4.begin()); + static_assert(std::is_same_v>); } template 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 e0052e499ca..3e456f566cc 100644 --- a/libstdc++-v3/testsuite/23_containers/multimap/cons/from_range.cc +++ b/libstdc++-v3/testsuite/23_containers/multimap/cons/from_range.cc @@ -44,9 +44,11 @@ test_deduction_guide() //__gnu_test::test_input_range> r3(0, 0); // std::multimap m6(std::from_range, r3); - // LWG4223: no deduction guide - // __gnu_test::test_input_range> r4(0, 0); - // std::multimap m7(std::from_range, r4); + __gnu_test::test_input_range> r4(0, 0); + std::multimap m7(std::from_range, r4); + static_assert(std::is_same_v>); + std::multimap it7(r4.begin(), r4.begin()); + static_assert(std::is_same_v>); } template 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 51f8538669a..6d1da5bf5d1 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 @@ -81,9 +81,11 @@ test_deduction_guide() // __gnu_test::test_input_range> r3(0, 0); // std::unordered_map m10(std::from_range, r3); - // LWG4223: no deduction guide - // __gnu_test::test_input_range> r4(0, 0); - // std::unordered_map m11(std::from_range, r4); + __gnu_test::test_input_range> r4(0, 0); + std::unordered_map m11(std::from_range, r4); + static_assert(std::is_same_v>); + std::unordered_map it11(r4.begin(), r4.begin()); + static_assert(std::is_same_v>); } template 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 1baf7305c84..2ca93d344e9 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 @@ -87,9 +87,15 @@ test_deduction_guide() // __gnu_test::test_input_range> r3(0, 0); // std::unordered_multimap m10(std::from_range, r3); - // LWG4223: no deduction guide - // __gnu_test::test_input_range> r4(0, 0); - // std::unordered_multimap m11(std::from_range, r4); + __gnu_test::test_input_range> r4(0, 0); + std::unordered_multimap m11(std::from_range, r4); + static_assert(std::is_same_v< + decltype(m11), + std::unordered_multimap>); + std::unordered_multimap it11(r4.begin(), r4.begin()); + static_assert(std::is_same_v< + decltype(it11), + std::unordered_multimap>); } template -- 2.47.2