]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Strip reference and cv-qual in range deduction guides for maps.
authorTomasz Kamiński <tkaminsk@redhat.com>
Thu, 20 Mar 2025 08:02:03 +0000 (09:02 +0100)
committerTomasz Kamiński <tkaminsk@redhat.com>
Mon, 28 Apr 2025 08:09:26 +0000 (10:09 +0200)
This implements part of LWG4223 that adjust the deduction guides for maps types
(map, unordered_map, flat_map and non-unique equivalent) from "range"
(std::from_range, iterator pair), 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.

Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
12 files changed:
libstdc++-v3/include/bits/ranges_base.h
libstdc++-v3/include/bits/stl_iterator.h
libstdc++-v3/testsuite/23_containers/flat_map/1.cc
libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc
libstdc++-v3/testsuite/23_containers/map/cons/deduction.cc
libstdc++-v3/testsuite/23_containers/map/cons/from_range.cc
libstdc++-v3/testsuite/23_containers/multimap/cons/deduction.cc
libstdc++-v3/testsuite/23_containers/multimap/cons/from_range.cc
libstdc++-v3/testsuite/23_containers/unordered_map/cons/deduction.cc
libstdc++-v3/testsuite/23_containers/unordered_map/cons/from_range.cc
libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/deduction.cc
libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/from_range.cc

index 488907da44668421b91a3955cff9a724026ce5d8..dde164988569b9ccb7f80086797fdf84c20214cb 100644 (file)
@@ -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>
index 9203a66b2ff04fc163a150fd47d1a4302999d6ab..bed72955d0c41392c935d040c3cc231e91024920 100644 (file)
@@ -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>
index 4fd33f616f78ce48b3596945236eb12cfc66cfc0..a4e0d867c93645d95ffd40fab3d5a12477375cb0 100644 (file)
@@ -56,16 +56,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());
index ea0d4b41e9fbaaa531a9a8acb73157ed107dad7c..1e70535286a4e0a6baa583cc541d9c69b2cf6562 100644 (file)
@@ -54,16 +54,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());
index f8e6e6e8b99427c88f89e0981d469db6fa861223..864598879b061fc5f578d6ea24423acc2db150bd 100644 (file)
@@ -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_cv_t<std::remove_reference_t<K>>;
+  using VD = std::remove_cv_t<std::remove_reference_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&>());
index 9935f44aa0f9fd69d17d42d92f9b5b10757bc658..3a9fede04348a26f37d28e53dd377393bfb70783 100644 (file)
@@ -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);
index f0699e2eefc38fc95e455dd30febe596050b920b..de5e6acb4f2498b7ce20f2304079543d2d5c4515 100644 (file)
@@ -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_cv_t<std::remove_reference_t<K>>;
+  using VD = std::remove_cv_t<std::remove_reference_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&>());
index 4a8ea9fec7d70a6b8e555a53a0156b265463d3d0..5907bab9878cef6b6e5222e2d4cdfa44989ba841 100644 (file)
@@ -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);
index fa182f5866d3fe40d3e4732eddcc6fbb22fd368d..26013da15c2fd593a6e05e104d5d066f14231322 100644 (file)
@@ -190,3 +190,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_cv_t<std::remove_reference_t<K>>;
+  using VD = std::remove_cv_t<std::remove_reference_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&>());
index 36efc2de5a396158b2db23db847b2a3d7e2f2cf7..04479a5e54d86f559ba8729a22afbfdca597df34 100644 (file)
@@ -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);
index 4de23fe3e791eacb1ee0f8befe65ecf7335af425..1db58a04abf81ae08f0b909edced4b6cad8b63ee 100644 (file)
@@ -205,3 +205,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_cv_t<std::remove_reference_t<K>>;
+  using VD = std::remove_cv_t<std::remove_reference_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&>());
index b551df49f3e71a4dd9d44907e53d5e1f5fb37f0d..4567bd8aa914f505e058eb20eb71f80aa57b2435 100644 (file)
@@ -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);