[PATCH] libstdc++: Support maps deduction from_range of tuples.

Jonathan Wakely jwakely@redhat.com
Wed Mar 19 11:56:22 GMT 2025


On 19/03/25 12:08 +0100, Tomasz Kamiński wrote:
>This implements part of LWG2713 that enables deduction for maps types

LWG 4223 not 2713

>(map, unordered_map, flat_map and non-unique equivalent) from
>(from_range, rg, ...) arguments, where rg is range of tuple
>and 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.
>---
>This implements non-controvesial part of LWG2713, which provides
>parity between iterator pair and from_range cosntructors.
>Testing on x86_64-linux (*map* tests passed).
>OK for trunk when test finishes?
>
> libstdc++-v3/include/bits/ranges_base.h       |  8 ++-
> .../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, 156 insertions(+), 14 deletions(-)
>
>diff --git a/libstdc++-v3/include/bits/ranges_base.h b/libstdc++-v3/include/bits/ranges_base.h
>index c9687c256e9..7d5aee9c430 100644
>--- a/libstdc++-v3/include/bits/ranges_base.h
>+++ b/libstdc++-v3/include/bits/ranges_base.h
>@@ -41,6 +41,10 @@
> #include <bits/max_size_type.h>
> #include <bits/version.h>
>
>+#if __glibcxx_ranges_to_container // C++ >= 23
>+# include <bits/utility.h> // for tuple_element_t
>+#endif
>+
> #pragma GCC diagnostic push
> #pragma GCC diagnostic ignored "-Wpedantic" // __int128
>
>@@ -1095,11 +1099,11 @@ namespace __detail
>

I think we should have a _GLIBCXX_RESOLVE_LIB_DEFECTS comment here, as
this changes something that was in the published C++23 standard. (We
only need one comment, since __range_mapped_type is right next to it.)

OK with that comment added, and the issue number in the commit message
fixed.

>   template<ranges::input_range _Range>
>     using __range_key_type
>-      = remove_const_t<typename ranges::range_value_t<_Range>::first_type>;
>+      = remove_const_t<tuple_element_t<0, ranges::range_value_t<_Range>>>;
>
>   template<ranges::input_range _Range>
>     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<ranges::input_range _Range>
>diff --git a/libstdc++-v3/testsuite/23_containers/flat_map/1.cc b/libstdc++-v3/testsuite/23_containers/flat_map/1.cc
>index 00254dc2ee6..4e5ac9b62b7 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 <vector>
> #include <testsuite_allocator.h>
> #include <testsuite_hooks.h>
>+#include <testsuite_iterators.h>
>+#include <tuple>
>+
>+struct Gt {
>+  template<typename T, typename U>
>+  bool operator()(T const& l, U const & r) const
>+  { return l > r; }
>+};
>+
>+void
>+test_deduction_guide()
>+{
>+  __gnu_test::test_input_range<std::pair<long, float>> r(0, 0);
>+  std::flat_map it1(std::from_range, r);
>+  static_assert(std::is_same_v<decltype(it1), std::flat_map<long, float>>);
>+  std::flat_map fr1(std::from_range, r);
>+  static_assert(std::is_same_v<decltype(fr1), std::flat_map<long, float>>);
>+
>+  Gt cmp;
>+  std::flat_map it2(r.begin(), r.begin(), cmp);
>+  static_assert(std::is_same_v<decltype(it2), std::flat_map<long, float, Gt>>);
>+  std::flat_map fr2(std::from_range, r, cmp);
>+  static_assert(std::is_same_v<decltype(fr2), std::flat_map<long, float, Gt>>);
>+
>+  using Alloc = __gnu_test::SimpleAllocator<std::pair<const long, float>>;
>+  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<long, float, std::less<long>,
>+		   std::vector<long, __gnu_test::SimpleAllocator<long>>,
>+		   std::vector<float, __gnu_test::SimpleAllocator<float>>>>);
>+
>+  // 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<long, float, Gt,
>+		   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::tuple<long, float>> r4(0, 0);
>+  std::flat_map it7(r4.begin(), r4.begin());
>+  static_assert(std::is_same_v<decltype(it7), std::flat_map<long, float>>);
>+  std::flat_map fr7(std::from_range, r4);
>+  static_assert(std::is_same_v<decltype(fr7), std::flat_map<long, float>>);
>+}
>
> template<template<typename> class KeyContainer, template<typename> 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..62bda65d79f 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 <vector>
> #include <testsuite_allocator.h>
> #include <testsuite_hooks.h>
>+#include <testsuite_iterators.h>
>+#include <tuple>
>+
>+struct Gt {
>+  template<typename T, typename U>
>+  bool operator()(T const& l, U const & r) const
>+  { return l > r; }
>+};
>+
>+void
>+test_deduction_guide()
>+{
>+  __gnu_test::test_input_range<std::pair<long, float>> r(0, 0);
>+  std::flat_multimap it1(std::from_range, r);
>+  static_assert(std::is_same_v<decltype(it1), std::flat_multimap<long, float>>);
>+  std::flat_multimap fr1(std::from_range, r);
>+  static_assert(std::is_same_v<decltype(fr1), std::flat_multimap<long, float>>);
>+
>+  Gt cmp;
>+  std::flat_multimap it2(r.begin(), r.begin(), cmp);
>+  static_assert(std::is_same_v<
>+    decltype(it2),
>+    std::flat_multimap<long, float, Gt>>);
>+  std::flat_multimap fr2(std::from_range, r, cmp);
>+  static_assert(std::is_same_v<
>+    decltype(fr2),
>+    std::flat_multimap<long, float, Gt>>);
>+
>+  using Alloc = __gnu_test::SimpleAllocator<std::pair<const long, float>>;
>+  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<long, float, std::less<long>,
>+		   std::vector<long, __gnu_test::SimpleAllocator<long>>,
>+		   std::vector<float, __gnu_test::SimpleAllocator<float>>>>);
>+
>+  // 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<long, float, Gt,
>+		   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::tuple<long, float>> r4(0, 0);
>+  std::flat_multimap it7(r4.begin(), r4.begin());
>+  static_assert(std::is_same_v<decltype(it7), std::flat_multimap<long, float>>);
>+  std::flat_multimap fr7(std::from_range, r4);
>+  static_assert(std::is_same_v<decltype(fr7), std::flat_multimap<long, float>>);
>+}
>
> template<template<typename> class KeyContainer, template<typename> 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<std::pair<const long&, float&>> r3(0, 0);
>   // std::map m6(std::from_range, r3);
>
>-  // LWG4223: no deduction guide
>-  // __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0);
>-  // std::map m7(std::from_range, r4);
>+  __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0);
>+  std::map m7(std::from_range, r4);
>+  static_assert(std::is_same_v<decltype(m7), std::map<long, float>>);
>+  std::map it7(r4.begin(), r4.begin());
>+  static_assert(std::is_same_v<decltype(it7), std::map<long, float>>);
> }
>
> template<typename T, typename U>
>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<std::pair<const long&, float&>> r3(0, 0);
>   // std::multimap m6(std::from_range, r3);
>
>-  // LWG4223: no deduction guide
>-  // __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0);
>-  // std::multimap m7(std::from_range, r4);
>+  __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0);
>+  std::multimap m7(std::from_range, r4);
>+  static_assert(std::is_same_v<decltype(m7), std::multimap<long, float>>);
>+  std::multimap it7(r4.begin(), r4.begin());
>+  static_assert(std::is_same_v<decltype(it7), std::multimap<long, float>>);
> }
>
> template<typename T, typename U>
>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 b3cbb2e6062..a15bfaa48b3 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
>@@ -82,9 +82,11 @@ test_deduction_guide()
>   // __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0);
>   // std::unordered_map m10(std::from_range, r3);
>
>-  // LWG4223: no deduction guide
>-  // __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0);
>-  // std::unordered_map m11(std::from_range, r4);
>+  __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0);
>+  std::unordered_map m11(std::from_range, r4);
>+  static_assert(std::is_same_v<decltype(m11), std::unordered_map<long, float>>);
>+  std::unordered_map it11(r4.begin(), r4.begin());
>+  static_assert(std::is_same_v<decltype(it11), std::unordered_map<long, float>>);
> }
>
> template<typename T, typename U>
>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 9273ef0d57a..416d9e08395 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<std::pair<const long&, float&>> r3(0, 0);
>   // std::unordered_multimap m10(std::from_range, r3);
>
>-  // LWG4223: no deduction guide
>-  // __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0);
>-  // std::unordered_multimap m11(std::from_range, r4);
>+  __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0);
>+  std::unordered_multimap m11(std::from_range, r4);
>+  static_assert(std::is_same_v<
>+    decltype(m11),
>+    std::unordered_multimap<long, float>>);
>+  std::unordered_multimap it11(r4.begin(), r4.begin());
>+  static_assert(std::is_same_v<
>+    decltype(it11),
>+    std::unordered_multimap<long, float>>);
> }
>
> template<typename T, typename U>
>-- 
>2.48.1
>
>



More information about the Libstdc++ mailing list