[libcxx-commits] [libcxx] [libc++] P2165R4: Update deduction guides for map containers and container adaptors (PR #136011)

via libcxx-commits libcxx-commits at lists.llvm.org
Tue May 27 11:08:39 PDT 2025


https://github.com/KSARK updated https://github.com/llvm/llvm-project/pull/136011

>From cd6c7989879ed9b9d798551ce279be329bf27a2c Mon Sep 17 00:00:00 2001
From: KSARK <hcwenyc at hotmail.com>
Date: Tue, 27 May 2025 18:05:56 +0000
Subject: [PATCH] [libc++] P2165R4: Update deduction guides for map containers
 and container adaptors

---
 libcxx/include/__iterator/iterator_traits.h   | 14 +++++++++++
 .../associative/map/map.cons/deduct.pass.cpp  | 20 ++++++++++++++++
 .../map/map.cons/deduct.verify.cpp            | 15 +++++++++++-
 .../multimap/multimap.cons/deduct.pass.cpp    | 21 +++++++++++++++++
 .../multimap/multimap.cons/deduct.verify.cpp  | 14 +++++++++++
 .../flat.map/flat.map.cons/deduct.pass.cpp    | 20 ++++++++++++++++
 .../flat.map/flat.map.cons/deduct.verify.cpp  | 14 +++++++++++
 .../flat.multimap.cons/deduct.pass.cpp        | 20 ++++++++++++++++
 .../flat.multimap.cons/deduct.verify.cpp      | 15 ++++++++++++
 .../unord.map/unord.map.cnstr/deduct.pass.cpp | 23 +++++++++++++++++++
 .../unord.map.cnstr/deduct.verify.cpp         | 14 +++++++++++
 .../unord.multimap.cnstr/deduct.pass.cpp      | 21 +++++++++++++++++
 .../unord.multimap.cnstr/deduct.verify.cpp    | 14 +++++++++++
 13 files changed, 224 insertions(+), 1 deletion(-)

diff --git a/libcxx/include/__iterator/iterator_traits.h b/libcxx/include/__iterator/iterator_traits.h
index c08d72971ec3e..8256580acb291 100644
--- a/libcxx/include/__iterator/iterator_traits.h
+++ b/libcxx/include/__iterator/iterator_traits.h
@@ -22,6 +22,7 @@
 #include <__fwd/pair.h>
 #include <__iterator/incrementable_traits.h>
 #include <__iterator/readable_traits.h>
+#include <__tuple/tuple_element.h>
 #include <__type_traits/common_reference.h>
 #include <__type_traits/conditional.h>
 #include <__type_traits/detected_or.h>
@@ -466,6 +467,18 @@ using __has_exactly_bidirectional_iterator_category _LIBCPP_NODEBUG =
 template <class _InputIterator>
 using __iter_value_type _LIBCPP_NODEBUG = typename iterator_traits<_InputIterator>::value_type;
 
+#if _LIBCPP_STD_VER >= 23
+template <class _InputIterator>
+using __iter_key_type _LIBCPP_NODEBUG = remove_const_t<tuple_element_t<0, __iter_value_type<_InputIterator>>>;
+
+template <class _InputIterator>
+using __iter_mapped_type _LIBCPP_NODEBUG = tuple_element_t<1, __iter_value_type<_InputIterator>>;
+
+template <class _InputIterator>
+using __iter_to_alloc_type _LIBCPP_NODEBUG =
+    pair<const tuple_element_t<0, __iter_value_type<_InputIterator>>,
+         tuple_element_t<1, __iter_value_type<_InputIterator>>>;
+#else
 template <class _InputIterator>
 using __iter_key_type _LIBCPP_NODEBUG =
     __remove_const_t<typename iterator_traits<_InputIterator>::value_type::first_type>;
@@ -477,6 +490,7 @@ template <class _InputIterator>
 using __iter_to_alloc_type _LIBCPP_NODEBUG =
     pair<const typename iterator_traits<_InputIterator>::value_type::first_type,
          typename iterator_traits<_InputIterator>::value_type::second_type>;
+#endif // _LIBCPP_STD_VER >= 23
 
 template <class _Iter>
 using __iterator_category_type _LIBCPP_NODEBUG = typename iterator_traits<_Iter>::iterator_category;
diff --git a/libcxx/test/std/containers/associative/map/map.cons/deduct.pass.cpp b/libcxx/test/std/containers/associative/map/map.cons/deduct.pass.cpp
index c91fe4b23566a..5cefb6f361a53 100644
--- a/libcxx/test/std/containers/associative/map/map.cons/deduct.pass.cpp
+++ b/libcxx/test/std/containers/associative/map/map.cons/deduct.pass.cpp
@@ -40,7 +40,10 @@
 #include <climits> // INT_MAX
 #include <functional>
 #include <map>
+#include <utility>
+#include <tuple>
 #include <type_traits>
+#include <vector>
 
 #include "deduction_guides_sfinae_checks.h"
 #include "test_allocator.h"
@@ -189,6 +192,23 @@ int main(int, char**) {
       static_assert(std::is_same_v<decltype(c), std::map<int, long, DefaultComp, Alloc>>);
     }
   }
+  {
+    std::vector<std::pair<const int, float>> pair_vec = {{1, 1.1f}, {2, 2.2f}, {3, 3.3f}};
+    std::map m1(pair_vec.begin(), pair_vec.end());
+    ASSERT_SAME_TYPE(decltype(m1), std::map<int, float>);
+
+    std::vector<std::tuple<int, double>> tuple_vec = {{10, 1.1}, {20, 2.2}, {30, 3.3}};
+    std::map m2(tuple_vec.begin(), tuple_vec.end());
+    ASSERT_SAME_TYPE(decltype(m2), std::map<int, double>);
+
+    std::vector<std::array<long, 2>> array_vec = {{100L, 101L}, {200L, 201L}, {300L, 301L}};
+    std::map m3(array_vec.begin(), array_vec.end());
+    ASSERT_SAME_TYPE(decltype(m3), std::map<long, long>);
+
+    std::vector<std::pair<int, char>> non_const_key_pair_vec = {{5, 'a'}, {6, 'b'}};
+    std::map m4(non_const_key_pair_vec.begin(), non_const_key_pair_vec.end());
+    ASSERT_SAME_TYPE(decltype(m4), std::map<int, char>);
+  }
 #endif
 
   AssociativeContainerDeductionGuidesSfinaeAway<std::map, std::map<int, long>>();
diff --git a/libcxx/test/std/containers/associative/map/map.cons/deduct.verify.cpp b/libcxx/test/std/containers/associative/map/map.cons/deduct.verify.cpp
index c8c0e1e538db2..8c00adca4f446 100644
--- a/libcxx/test/std/containers/associative/map/map.cons/deduct.verify.cpp
+++ b/libcxx/test/std/containers/associative/map/map.cons/deduct.verify.cpp
@@ -26,9 +26,11 @@
 // map(initializer_list<Key>, Allocator)
 //   -> map<Key, less<Key>, Allocator>;
 
+#include <array>
 #include <climits> // INT_MAX
 #include <functional>
 #include <map>
+#include <tuple>
 #include <type_traits>
 
 struct NotAnAllocator {
@@ -101,6 +103,17 @@ int main(int, char**) {
     std::map m(PC{1, 1L});
     // expected-error-re at -1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}map'}}
   }
-
+  {
+    // cannot deduce from tuple-like objects without proper iterator
+    std::tuple<int, double> t{1, 2.0};
+    std::map m(t);
+    // expected-error-re at -1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}map'}}
+  }
+  {
+    // cannot deduce from array-like objects without proper iterator
+    std::array<int, 2> arr{1, 2};
+    std::map m(arr);
+    // expected-error-re at -1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}map'}}
+  }
   return 0;
 }
diff --git a/libcxx/test/std/containers/associative/multimap/multimap.cons/deduct.pass.cpp b/libcxx/test/std/containers/associative/multimap/multimap.cons/deduct.pass.cpp
index 2f3db7f0de992..1e318890e58ac 100644
--- a/libcxx/test/std/containers/associative/multimap/multimap.cons/deduct.pass.cpp
+++ b/libcxx/test/std/containers/associative/multimap/multimap.cons/deduct.pass.cpp
@@ -40,7 +40,10 @@
 #include <climits> // INT_MAX
 #include <functional>
 #include <map>
+#include <tuple>
 #include <type_traits>
+#include <utility>
+#include <vector>
 
 #include "deduction_guides_sfinae_checks.h"
 #include "test_allocator.h"
@@ -189,6 +192,24 @@ int main(int, char**) {
       static_assert(std::is_same_v<decltype(c), std::multimap<int, long, DefaultComp, Alloc>>);
     }
   }
+  {
+    std::vector<std::pair<const int, float>> pair_vec = {{1, 1.1f}, {2, 2.2f}, {3, 3.3f}};
+    std::multimap mm1(pair_vec.begin(), pair_vec.end());
+    ASSERT_SAME_TYPE(decltype(mm1), std::multimap<int, float>);
+
+    std::vector<std::tuple<int, double>> tuple_vec = {{10, 1.1}, {20, 2.2}, {30, 3.3}};
+    std::multimap mm2(tuple_vec.begin(), tuple_vec.end());
+    ASSERT_SAME_TYPE(decltype(mm2), std::multimap<int, double>);
+
+    std::vector<std::array<long, 2>> array_vec = {{100L, 101L}, {200L, 201L}, {300L, 301L}};
+    std::multimap mm3(array_vec.begin(), array_vec.end());
+    ASSERT_SAME_TYPE(decltype(mm3), std::multimap<long, long>);
+
+    // Check deduction with non-const key in input pair
+    std::vector<std::pair<int, char>> non_const_key_pair_vec = {{5, 'a'}, {6, 'b'}};
+    std::multimap mm4(non_const_key_pair_vec.begin(), non_const_key_pair_vec.end());
+    ASSERT_SAME_TYPE(decltype(mm4), std::multimap<int, char>);
+  }
 #endif
 
   AssociativeContainerDeductionGuidesSfinaeAway<std::multimap, std::multimap<int, long>>();
diff --git a/libcxx/test/std/containers/associative/multimap/multimap.cons/deduct.verify.cpp b/libcxx/test/std/containers/associative/multimap/multimap.cons/deduct.verify.cpp
index 03ac8ebf92716..aa642e39bec17 100644
--- a/libcxx/test/std/containers/associative/multimap/multimap.cons/deduct.verify.cpp
+++ b/libcxx/test/std/containers/associative/multimap/multimap.cons/deduct.verify.cpp
@@ -26,9 +26,11 @@
 // multimap(initializer_list<Key>, Allocator)
 //   -> multimap<Key, less<Key>, Allocator>;
 
+#include <array>
 #include <climits> // INT_MAX
 #include <functional>
 #include <map>
+#include <tuple>
 #include <type_traits>
 
 struct NotAnAllocator {
@@ -101,6 +103,18 @@ int main(int, char**) {
     std::multimap m(PC{1, 1L});
     // expected-error-re at -1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}multimap'}}
   }
+  {
+    // cannot deduce from tuple-like objects without proper iterator
+    std::tuple<int, double> t{1, 2.0};
+    std::multimap m(t);
+    // expected-error-re at -1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}multimap'}}
+  }
+  {
+    // cannot deduce from array-like objects without proper iterator
+    std::array<int, 2> arr{1, 2};
+    std::multimap m(arr);
+    // expected-error-re at -1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}multimap'}}
+  }
 
   return 0;
 }
diff --git a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.cons/deduct.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.cons/deduct.pass.cpp
index 009392feb3862..21166361b014b 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.cons/deduct.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.cons/deduct.pass.cpp
@@ -11,6 +11,7 @@
 // <flat_map>
 
 #include <algorithm>
+#include <array>
 #include <cassert>
 #include <climits>
 #include <deque>
@@ -19,6 +20,7 @@
 #include <flat_map>
 #include <functional>
 #include <ranges>
+#include <tuple>
 #include <type_traits>
 #include <utility>
 #include <vector>
@@ -335,6 +337,24 @@ int main(int, char**) {
   test_from_range();
   test_from_range_compare();
 
+#if TEST_STD_VER >= 23
+  std::vector<std::pair<const int, float>> pair_vec = {{1, 1.1f}, {2, 2.2f}, {3, 3.3f}};
+  std::flat_map fm1(pair_vec.begin(), pair_vec.end());
+  ASSERT_SAME_TYPE(decltype(fm1), std::flat_map<int, float>);
+
+  std::vector<std::tuple<int, double>> tuple_vec = {{10, 1.1}, {20, 2.2}, {30, 3.3}};
+  std::flat_map fm2(tuple_vec.begin(), tuple_vec.end());
+  ASSERT_SAME_TYPE(decltype(fm2), std::flat_map<int, double>);
+
+  std::vector<std::array<long, 2>> array_vec = {{100L, 101L}, {200L, 201L}, {300L, 301L}};
+  std::flat_map fm3(array_vec.begin(), array_vec.end());
+  ASSERT_SAME_TYPE(decltype(fm3), std::flat_map<long, long>);
+
+  std::vector<std::pair<int, char>> non_const_key_pair_vec = {{5, 'a'}, {6, 'b'}};
+  std::flat_map fm4(non_const_key_pair_vec.begin(), non_const_key_pair_vec.end());
+  ASSERT_SAME_TYPE(decltype(fm4), std::flat_map<int, char>);
+#endif
+
   AssociativeContainerDeductionGuidesSfinaeAway<std::flat_map, std::flat_map<int, short>>();
 
   return 0;
diff --git a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.cons/deduct.verify.cpp b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.cons/deduct.verify.cpp
index ed20c1ae715b8..6f0d802e8e236 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.cons/deduct.verify.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.cons/deduct.verify.cpp
@@ -12,9 +12,11 @@
 
 // Test CTAD on cases where deduction should fail.
 
+#include <array>
 #include <flat_map>
 #include <functional>
 #include <utility>
+#include <tuple>
 
 using P  = std::pair<int, long>;
 using PC = std::pair<const int, long>;
@@ -50,4 +52,16 @@ void test() {
     std::flat_map m(PC{1, 1L});
     // expected-error-re at -1{{{{no viable constructor or deduction guide for deduction of template arguments of '.*flat_map'}}}}
   }
+  {
+    // cannot deduce from tuple-like objects without proper iterator
+    std::tuple<int, double> t{1, 2.0};
+    std::flat_map m(t);
+    // expected-error-re at -1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}flat_map'}}
+  }
+  {
+    // cannot deduce from array-like objects without proper iterator
+    std::array<int, 2> arr{1, 2};
+    std::flat_map m(arr);
+    // expected-error-re at -1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}flat_map'}}
+  }
 }
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/deduct.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/deduct.pass.cpp
index a718d9cfad5b7..23ef312a5c67c 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/deduct.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/deduct.pass.cpp
@@ -11,6 +11,7 @@
 // <flat_map>
 
 #include <algorithm>
+#include <array>
 #include <cassert>
 #include <climits>
 #include <deque>
@@ -325,6 +326,24 @@ void test_from_range_compare() {
   }
 }
 
+void test_tuple_like_deduction() {
+  std::vector<std::pair<const int, float>> pair_vec = {{1, 1.1f}, {2, 2.2f}, {3, 3.3f}};
+  std::flat_multimap fmm1(pair_vec.begin(), pair_vec.end());
+  ASSERT_SAME_TYPE(decltype(fmm1), std::flat_multimap<int, float>);
+
+  std::vector<std::tuple<int, double>> tuple_vec = {{10, 1.1}, {20, 2.2}, {30, 3.3}};
+  std::flat_multimap fmm2(tuple_vec.begin(), tuple_vec.end());
+  ASSERT_SAME_TYPE(decltype(fmm2), std::flat_multimap<int, double>);
+
+  std::vector<std::array<long, 2>> array_vec = {{100L, 101L}, {200L, 201L}, {300L, 301L}};
+  std::flat_multimap fmm3(array_vec.begin(), array_vec.end());
+  ASSERT_SAME_TYPE(decltype(fmm3), std::flat_multimap<long, long>);
+
+  std::vector<std::pair<int, char>> non_const_key_pair_vec = {{5, 'a'}, {6, 'b'}};
+  std::flat_multimap fmm4(non_const_key_pair_vec.begin(), non_const_key_pair_vec.end());
+  ASSERT_SAME_TYPE(decltype(fmm4), std::flat_multimap<int, char>);
+}
+
 int main(int, char**) {
   // Each test function also tests the sorted_equivalent-prefixed and allocator-suffixed overloads.
   test_copy();
@@ -336,6 +355,7 @@ int main(int, char**) {
   test_initializer_list_compare();
   test_from_range();
   test_from_range_compare();
+  test_tuple_like_deduction();
 
   AssociativeContainerDeductionGuidesSfinaeAway<std::flat_multimap, std::flat_multimap<int, short>>();
 
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/deduct.verify.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/deduct.verify.cpp
index c25218e890f21..316c73075fcc1 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/deduct.verify.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.cons/deduct.verify.cpp
@@ -12,8 +12,10 @@
 
 // Test CTAD on cases where deduction should fail.
 
+#include <array>
 #include <flat_map>
 #include <functional>
+#include <tuple>
 #include <utility>
 
 struct NotAnAllocator {
@@ -54,4 +56,17 @@ void test() {
     std::flat_multimap m(PC{1, 1L});
     // expected-error-re at -1{{{{no viable constructor or deduction guide for deduction of template arguments of '.*flat_multimap'}}}}
   }
+  {
+    // cannot deduce from tuple-like objects without proper iterator
+    std::tuple<int, double> t{1, 2.0};
+    std::flat_multimap m(t);
+    // expected-error-re at -1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}flat_multimap'}}
+  }
+  {
+    // cannot deduce from array-like objects without proper iterator
+    std::array<int, 2> arr{1, 2};
+    std::flat_multimap m(arr);
+    // expected-error-re at -1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}flat_multimap'}}
+  }
+  return 0;
 }
diff --git a/libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/deduct.pass.cpp b/libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/deduct.pass.cpp
index b2ef6be5523a5..2396fbd1002c3 100644
--- a/libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/deduct.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/deduct.pass.cpp
@@ -82,8 +82,11 @@
 #include <cassert>
 #include <climits> // INT_MAX
 #include <iterator>
+#include <tuple>
 #include <type_traits>
 #include <unordered_map>
+#include <utility>
+#include <vector>
 
 #include "../../../test_compare.h"
 #include "../../../test_hash.h"
@@ -311,6 +314,26 @@ int main(int, char**) {
       static_assert(std::is_same_v<decltype(c), std::unordered_map<int, long, Hash, DefaultPred, Alloc>>);
     }
   }
+  {
+    std::vector<std::pair<const int, float>> pair_vec = {{1, 1.1f}, {2, 2.2f}, {3, 3.3f}};
+    std::unordered_map um1(pair_vec.begin(), pair_vec.end());
+    ASSERT_SAME_TYPE(decltype(um1), std::unordered_map<int, float>);
+
+    std::vector<std::tuple<int, double>> tuple_vec = {{10, 1.1}, {20, 2.2}, {30, 3.3}};
+    // Note: std::tuple needs a hash specialization to be used as a key in unordered containers.
+    // This static_assert only checks the deduced type.
+    std::unordered_map um2(tuple_vec.begin(), tuple_vec.end());
+    ASSERT_SAME_TYPE(decltype(um2), std::unordered_map<int, double>);
+
+    std::vector<std::array<long, 2>> array_vec = {{100L, 101L}, {200L, 201L}, {300L, 301L}};
+    // Note: std::array needs a hash specialization.
+    std::unordered_map um3(array_vec.begin(), array_vec.end());
+    ASSERT_SAME_TYPE(decltype(um3), std::unordered_map<long, long>);
+
+    std::vector<std::pair<int, char>> non_const_key_pair_vec = {{5, 'a'}, {6, 'b'}};
+    std::unordered_map um4(non_const_key_pair_vec.begin(), non_const_key_pair_vec.end());
+    ASSERT_SAME_TYPE(decltype(um4), std::unordered_map<int, char>);
+  }
 #endif
 
   UnorderedContainerDeductionGuidesSfinaeAway<std::unordered_map, std::unordered_map<int, long>>();
diff --git a/libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/deduct.verify.cpp b/libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/deduct.verify.cpp
index 5bb2b28fa09f5..017bf122c7230 100644
--- a/libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/deduct.verify.cpp
+++ b/libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/deduct.verify.cpp
@@ -56,7 +56,9 @@
 //               Allocator)
 //   -> unordered_map<Key, T, Hash, equal_to<Key>, Allocator>;
 
+#include <array>
 #include <functional>
+#include <tuple>
 #include <unordered_map>
 
 int main(int, char**) {
@@ -101,6 +103,18 @@ int main(int, char**) {
     std::unordered_map m(42, std::hash<int>(), std::allocator<P>());
     // expected-error-re at -1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}unordered_map'}}
   }
+  {
+    // cannot deduce from tuple-like objects without proper iterator
+    std::tuple<int, double> t{1, 2.0};
+    std::unordered_map m(t);
+    // expected-error-re at -1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}unordered_map'}}
+  }
+  {
+    // cannot deduce from array-like objects without proper iterator
+    std::array<int, 2> arr{1, 2};
+    std::unordered_map m(arr);
+    // expected-error-re at -1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}unordered_map'}}
+  }
 
   return 0;
 }
diff --git a/libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/deduct.pass.cpp b/libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/deduct.pass.cpp
index 5d625a1deaab5..39896c6fe4ef1 100644
--- a/libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/deduct.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/deduct.pass.cpp
@@ -81,8 +81,11 @@
 #include <array>
 #include <cassert>
 #include <climits> // INT_MAX
+#include <tuple>
 #include <type_traits>
 #include <unordered_map>
+#include <utility>
+#include <vector>
 
 #include "../../../test_compare.h"
 #include "../../../test_hash.h"
@@ -307,6 +310,24 @@ int main(int, char**) {
       static_assert(std::is_same_v<decltype(c), std::unordered_multimap<int, long, Hash, DefaultPred, Alloc>>);
     }
   }
+
+  {
+    std::vector<std::pair<const int, float>> pair_vec = {{1, 1.1f}, {2, 2.2f}, {3, 3.3f}};
+    std::unordered_multimap umm1(pair_vec.begin(), pair_vec.end());
+    ASSERT_SAME_TYPE(decltype(umm1), std::unordered_multimap<int, float>);
+
+    std::vector<std::tuple<int, double>> tuple_vec = {{10, 1.1}, {20, 2.2}, {30, 3.3}};
+    std::unordered_multimap umm2(tuple_vec.begin(), tuple_vec.end());
+    ASSERT_SAME_TYPE(decltype(umm2), std::unordered_multimap<int, double>);
+
+    std::vector<std::array<long, 2>> array_vec = {{100L, 101L}, {200L, 201L}, {300L, 301L}};
+    std::unordered_multimap umm3(array_vec.begin(), array_vec.end());
+    ASSERT_SAME_TYPE(decltype(umm3), std::unordered_multimap<long, long>);
+
+    std::vector<std::pair<int, char>> non_const_key_pair_vec = {{5, 'a'}, {6, 'b'}};
+    std::unordered_multimap umm4(non_const_key_pair_vec.begin(), non_const_key_pair_vec.end());
+    ASSERT_SAME_TYPE(decltype(umm4), std::unordered_multimap<int, char>);
+  }
 #endif
 
   UnorderedContainerDeductionGuidesSfinaeAway<std::unordered_multimap, std::unordered_multimap<int, long>>();
diff --git a/libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/deduct.verify.cpp b/libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/deduct.verify.cpp
index 11410ef2da9a4..dad8293b4b342 100644
--- a/libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/deduct.verify.cpp
+++ b/libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/deduct.verify.cpp
@@ -56,7 +56,9 @@
 //               Allocator)
 //   -> unordered_multimap<Key, T, Hash, equal_to<Key>, Allocator>;
 
+#include <array>
 #include <functional>
+#include <tuple>
 #include <unordered_map>
 
 int main(int, char**) {
@@ -101,6 +103,18 @@ int main(int, char**) {
     std::unordered_multimap m(42, std::hash<int>(), std::allocator<P>());
     // expected-error-re at -1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}unordered_multimap'}}
   }
+  {
+    // cannot deduce from tuple-like objects without proper iterator
+    std::tuple<int, double> t{1, 2.0};
+    std::unordered_multimap m(t);
+    // expected-error-re at -1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}unordered_multimap'}}
+  }
+  {
+    // cannot deduce from array-like objects without proper iterator
+    std::array<int, 2> arr{1, 2};
+    std::unordered_multimap m(arr);
+    // expected-error-re at -1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}unordered_multimap'}}
+  }
 
   return 0;
 }



More information about the libcxx-commits mailing list