diff --git a/libcxx/docs/Cxx2bStatusPaperStatus.csv b/libcxx/docs/Cxx2bStatusPaperStatus.csv --- a/libcxx/docs/Cxx2bStatusPaperStatus.csv +++ b/libcxx/docs/Cxx2bStatusPaperStatus.csv @@ -11,3 +11,5 @@ "`P2212R2 `__","LWG","Relax Requirements for time_point::clock","February 2021","","" "`P2259R1 `__","LWG","Repairing input range adaptors and counted_iterator","February 2021","","" "","","","","","" +"`P1518R2 `__","LWG","Stop overconstraining allocators in container deduction guides","June 2021","|Complete|","13.0" +"","","","","","" diff --git a/libcxx/include/deque b/libcxx/include/deque --- a/libcxx/include/deque +++ b/libcxx/include/deque @@ -1317,7 +1317,7 @@ deque(_InputIter __f, _InputIter __l, const allocator_type& __a, typename enable_if<__is_cpp17_input_iterator<_InputIter>::value>::type* = 0); deque(const deque& __c); - deque(const deque& __c, const allocator_type& __a); + deque(const deque& __c, const __identity_t& __a); deque& operator=(const deque& __c); @@ -1331,7 +1331,7 @@ _LIBCPP_INLINE_VISIBILITY deque(deque&& __c) _NOEXCEPT_(is_nothrow_move_constructible<__base>::value); _LIBCPP_INLINE_VISIBILITY - deque(deque&& __c, const allocator_type& __a); + deque(deque&& __c, const __identity_t& __a); _LIBCPP_INLINE_VISIBILITY deque& operator=(deque&& __c) _NOEXCEPT_(__alloc_traits::propagate_on_container_move_assignment::value && @@ -1660,7 +1660,7 @@ } template -deque<_Tp, _Allocator>::deque(const deque& __c, const allocator_type& __a) +deque<_Tp, _Allocator>::deque(const deque& __c, const __identity_t& __a) : __base(__a) { __append(__c.begin(), __c.end()); @@ -1703,7 +1703,7 @@ template inline -deque<_Tp, _Allocator>::deque(deque&& __c, const allocator_type& __a) +deque<_Tp, _Allocator>::deque(deque&& __c, const __identity_t& __a) : __base(_VSTD::move(__c), __a) { if (__a != __c.__alloc()) diff --git a/libcxx/include/forward_list b/libcxx/include/forward_list --- a/libcxx/include/forward_list +++ b/libcxx/include/forward_list @@ -681,7 +681,7 @@ __is_cpp17_input_iterator<_InputIterator>::value >::type* = nullptr); forward_list(const forward_list& __x); - forward_list(const forward_list& __x, const allocator_type& __a); + forward_list(const forward_list& __x, const __identity_t& __a); forward_list& operator=(const forward_list& __x); @@ -690,7 +690,7 @@ forward_list(forward_list&& __x) _NOEXCEPT_(is_nothrow_move_constructible::value) : base(_VSTD::move(__x)) {} - forward_list(forward_list&& __x, const allocator_type& __a); + forward_list(forward_list&& __x, const __identity_t& __a); forward_list(initializer_list __il); forward_list(initializer_list __il, const allocator_type& __a); @@ -979,7 +979,7 @@ template forward_list<_Tp, _Alloc>::forward_list(const forward_list& __x, - const allocator_type& __a) + const __identity_t& __a) : base(__a) { insert_after(cbefore_begin(), __x.begin(), __x.end()); @@ -1000,7 +1000,7 @@ #ifndef _LIBCPP_CXX03_LANG template forward_list<_Tp, _Alloc>::forward_list(forward_list&& __x, - const allocator_type& __a) + const __identity_t& __a) : base(_VSTD::move(__x), __a) { if (base::__alloc() != __x.__alloc()) diff --git a/libcxx/include/list b/libcxx/include/list --- a/libcxx/include/list +++ b/libcxx/include/list @@ -893,7 +893,7 @@ typename enable_if<__is_cpp17_input_iterator<_InpIter>::value>::type* = 0); list(const list& __c); - list(const list& __c, const allocator_type& __a); + list(const list& __c, const __identity_t& __a); _LIBCPP_INLINE_VISIBILITY list& operator=(const list& __c); #ifndef _LIBCPP_CXX03_LANG @@ -904,7 +904,7 @@ list(list&& __c) _NOEXCEPT_(is_nothrow_move_constructible<__node_allocator>::value); _LIBCPP_INLINE_VISIBILITY - list(list&& __c, const allocator_type& __a); + list(list&& __c, const __identity_t& __a); _LIBCPP_INLINE_VISIBILITY list& operator=(list&& __c) _NOEXCEPT_( @@ -1286,7 +1286,7 @@ } template -list<_Tp, _Alloc>::list(const list& __c, const allocator_type& __a) +list<_Tp, _Alloc>::list(const list& __c, const __identity_t& __a) : base(__a) { #if _LIBCPP_DEBUG_LEVEL == 2 @@ -1333,7 +1333,7 @@ template inline -list<_Tp, _Alloc>::list(list&& __c, const allocator_type& __a) +list<_Tp, _Alloc>::list(list&& __c, const __identity_t& __a) : base(__a) { #if _LIBCPP_DEBUG_LEVEL == 2 diff --git a/libcxx/include/queue b/libcxx/include/queue --- a/libcxx/include/queue +++ b/libcxx/include/queue @@ -339,7 +339,7 @@ template::value>, - class = _EnableIf<__is_allocator<_Alloc>::value> + class = _EnableIf::value> > queue(_Container, _Alloc) -> queue; @@ -554,7 +554,7 @@ class _Alloc, class = _EnableIf::value>, class = _EnableIf::value>, - class = _EnableIf<__is_allocator<_Alloc>::value> + class = _EnableIf::value> > priority_queue(_Compare, _Container, _Alloc) -> priority_queue; diff --git a/libcxx/include/stack b/libcxx/include/stack --- a/libcxx/include/stack +++ b/libcxx/include/stack @@ -239,7 +239,7 @@ template::value>, - class = _EnableIf<__is_allocator<_Alloc>::value> + class = _EnableIf::value> > stack(_Container, _Alloc) -> stack; diff --git a/libcxx/include/vector b/libcxx/include/vector --- a/libcxx/include/vector +++ b/libcxx/include/vector @@ -557,7 +557,7 @@ } vector(const vector& __x); - vector(const vector& __x, const allocator_type& __a); + vector(const vector& __x, const __identity_t& __a); _LIBCPP_INLINE_VISIBILITY vector& operator=(const vector& __x); @@ -577,7 +577,7 @@ #endif _LIBCPP_INLINE_VISIBILITY - vector(vector&& __x, const allocator_type& __a); + vector(vector&& __x, const __identity_t& __a); _LIBCPP_INLINE_VISIBILITY vector& operator=(vector&& __x) _NOEXCEPT_((__noexcept_move_assign_container<_Allocator, __alloc_traits>::value)); @@ -1261,7 +1261,7 @@ } template -vector<_Tp, _Allocator>::vector(const vector& __x, const allocator_type& __a) +vector<_Tp, _Allocator>::vector(const vector& __x, const __identity_t& __a) : __base(__a) { #if _LIBCPP_DEBUG_LEVEL == 2 @@ -1299,7 +1299,7 @@ template inline _LIBCPP_INLINE_VISIBILITY -vector<_Tp, _Allocator>::vector(vector&& __x, const allocator_type& __a) +vector<_Tp, _Allocator>::vector(vector&& __x, const __identity_t& __a) : __base(__a) { #if _LIBCPP_DEBUG_LEVEL == 2 @@ -2261,7 +2261,7 @@ #else _NOEXCEPT_(is_nothrow_move_constructible::value); #endif - vector(vector&& __v, const allocator_type& __a); + vector(vector&& __v, const __identity_t& __a); _LIBCPP_INLINE_VISIBILITY vector& operator=(vector&& __v) _NOEXCEPT_((__noexcept_move_assign_container<_Allocator, __alloc_traits>::value)); @@ -2887,7 +2887,7 @@ } template -vector::vector(vector&& __v, const allocator_type& __a) +vector::vector(vector&& __v, const __identity_t& __a) : __begin_(nullptr), __size_(0), __cap_alloc_(0, __a) 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 --- a/libcxx/test/std/containers/associative/map/map.cons/deduct.pass.cpp +++ b/libcxx/test/std/containers/associative/map/map.cons/deduct.pass.cpp @@ -133,5 +133,24 @@ assert(m.get_allocator().get_id() == 45); } + { + // Examples from LWG3025 + std::map m{std::pair{1, 1}, {2, 2}, {3, 3}}; + ASSERT_SAME_TYPE(decltype(m), std::map); + + std::map m2{m.begin(), m.end()}; + ASSERT_SAME_TYPE(decltype(m2), std::map); + } + + { + // Examples from LWG3531 + std::map m1{{std::pair{1, 2}, {3, 4}}, std::less()}; + ASSERT_SAME_TYPE(decltype(m1), std::map); + + using value_type = std::pair; + std::map m2{{value_type{1, 2}, {3, 4}}, std::less()}; + ASSERT_SAME_TYPE(decltype(m2), 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 --- a/libcxx/test/std/containers/associative/multimap/multimap.cons/deduct.pass.cpp +++ b/libcxx/test/std/containers/associative/multimap/multimap.cons/deduct.pass.cpp @@ -133,5 +133,24 @@ assert(m.get_allocator().get_id() == 45); } + { + // Examples from LWG3025 + std::multimap m{std::pair{1, 1}, {2, 2}, {3, 3}}; + ASSERT_SAME_TYPE(decltype(m), std::multimap); + + std::multimap m2{m.begin(), m.end()}; + ASSERT_SAME_TYPE(decltype(m2), std::multimap); + } + + { + // Examples from LWG3531 + std::multimap m1{{std::pair{1, 2}, {3, 4}}, std::less()}; + ASSERT_SAME_TYPE(decltype(m1), std::multimap); + + using value_type = std::pair; + std::multimap m2{{value_type{1, 2}, {3, 4}}, std::less()}; + ASSERT_SAME_TYPE(decltype(m2), std::multimap); + } + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/priority.queue/priqueue.cons/deduct.pass.cpp b/libcxx/test/std/containers/container.adaptors/priority.queue/priqueue.cons/deduct.pass.cpp --- a/libcxx/test/std/containers/container.adaptors/priority.queue/priqueue.cons/deduct.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/priority.queue/priqueue.cons/deduct.pass.cpp @@ -104,21 +104,76 @@ } { -// This one is odd - you can pass an allocator in to use, but the allocator -// has to match the type of the one used by the underlying container - typedef long double T; - typedef std::greater Comp; - typedef test_allocator Alloc; - typedef std::deque Cont; - - Cont c{2,3,0,1}; - std::priority_queue source(Comp(), c); - std::priority_queue pri(source, Alloc(2)); // queue(queue &, allocator) - static_assert(std::is_same_v, ""); - static_assert(std::is_same_v, ""); - assert(pri.size() == 4); - assert(pri.top() == 0); + typedef short T; + typedef std::greater Comp; + typedef test_allocator Alloc; + typedef std::deque Cont; + typedef test_allocator ConvertibleToAlloc; + static_assert(std::uses_allocator_v && + !std::is_same_v); + + { + Comp comp; + Cont cont; + std::priority_queue pri(comp, cont, Alloc(2)); + static_assert(std::is_same_v>); + } + + { + Comp comp; + Cont cont; + std::priority_queue pri(comp, cont, ConvertibleToAlloc(2)); + static_assert(std::is_same_v>); + } + + { + Comp comp; + Cont cont; + std::priority_queue pri(comp, std::move(cont), Alloc(2)); + static_assert(std::is_same_v>); + } + + { + Comp comp; + Cont cont; + std::priority_queue pri(comp, std::move(cont), ConvertibleToAlloc(2)); + static_assert(std::is_same_v>); + } + } + + { + typedef short T; + typedef std::greater Comp; + typedef test_allocator Alloc; + typedef std::deque Cont; + typedef test_allocator ConvertibleToAlloc; + static_assert(std::uses_allocator_v && + !std::is_same_v); + + { + std::priority_queue source; + std::priority_queue pri(source, Alloc(2)); + static_assert(std::is_same_v>); + } + + { + std::priority_queue source; + std::priority_queue pri(source, ConvertibleToAlloc(2)); + static_assert(std::is_same_v>); + } + + { + std::priority_queue source; + std::priority_queue pri(std::move(source), Alloc(2)); + static_assert(std::is_same_v>); + } + + { + std::priority_queue source; + std::priority_queue pri(std::move(source), ConvertibleToAlloc(2)); + static_assert(std::is_same_v>); + } } - return 0; + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/queue/queue.cons/deduct.pass.cpp b/libcxx/test/std/containers/container.adaptors/queue/queue.cons/deduct.pass.cpp --- a/libcxx/test/std/containers/container.adaptors/queue/queue.cons/deduct.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/queue/queue.cons/deduct.pass.cpp @@ -72,21 +72,70 @@ } { -// This one is odd - you can pass an allocator in to use, but the allocator -// has to match the type of the one used by the underlying container - typedef short T; - typedef test_allocator Alloc; - typedef std::deque Container; - - Container c{0,1,2,3}; - std::queue source(c); - std::queue que(source, Alloc(2)); // queue(queue &, allocator) - static_assert(std::is_same_v, ""); - static_assert(std::is_same_v, ""); - assert(que.size() == 4); - assert(que.back() == 3); + typedef short T; + typedef test_allocator Alloc; + typedef std::list Cont; + typedef test_allocator ConvertibleToAlloc; + static_assert(std::uses_allocator_v && + !std::is_same_v); + + { + Cont cont; + std::queue que(cont, Alloc(2)); + static_assert(std::is_same_v>); + } + + { + Cont cont; + std::queue que(cont, ConvertibleToAlloc(2)); + static_assert(std::is_same_v>); + } + + { + Cont cont; + std::queue que(std::move(cont), Alloc(2)); + static_assert(std::is_same_v>); + } + + { + Cont cont; + std::queue que(std::move(cont), ConvertibleToAlloc(2)); + static_assert(std::is_same_v>); + } } + { + typedef short T; + typedef test_allocator Alloc; + typedef std::list Cont; + typedef test_allocator ConvertibleToAlloc; + static_assert(std::uses_allocator_v && + !std::is_same_v); + + { + std::queue source; + std::queue que(source, Alloc(2)); + static_assert(std::is_same_v>); + } + + { + std::queue source; + std::queue que(source, ConvertibleToAlloc(2)); + static_assert(std::is_same_v>); + } + + { + std::queue source; + std::queue que(std::move(source), Alloc(2)); + static_assert(std::is_same_v>); + } + + { + std::queue source; + std::queue que(std::move(source), ConvertibleToAlloc(2)); + static_assert(std::is_same_v>); + } + } - return 0; + return 0; } diff --git a/libcxx/test/std/containers/container.adaptors/stack/stack.cons/deduct.pass.cpp b/libcxx/test/std/containers/container.adaptors/stack/stack.cons/deduct.pass.cpp --- a/libcxx/test/std/containers/container.adaptors/stack/stack.cons/deduct.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/stack/stack.cons/deduct.pass.cpp @@ -22,6 +22,7 @@ #include +#include #include #include #include @@ -75,21 +76,70 @@ } { -// This one is odd - you can pass an allocator in to use, but the allocator -// has to match the type of the one used by the underlying container - typedef short T; - typedef test_allocator Alloc; - typedef std::deque Container; - - Container c{0,1,2,3}; - std::stack source(c); - std::stack stk(source, Alloc(2)); // stack(stack &, allocator) - static_assert(std::is_same_v, ""); - static_assert(std::is_same_v, ""); - assert(stk.size() == 4); - assert(stk.top() == 3); + typedef short T; + typedef test_allocator Alloc; + typedef std::list Cont; + typedef test_allocator ConvertibleToAlloc; + static_assert(std::uses_allocator_v && + !std::is_same_v); + + { + Cont cont; + std::stack stk(cont, Alloc(2)); + static_assert(std::is_same_v>); + } + + { + Cont cont; + std::stack stk(cont, ConvertibleToAlloc(2)); + static_assert(std::is_same_v>); + } + + { + Cont cont; + std::stack stk(std::move(cont), Alloc(2)); + static_assert(std::is_same_v>); + } + + { + Cont cont; + std::stack stk(std::move(cont), ConvertibleToAlloc(2)); + static_assert(std::is_same_v>); + } } + { + typedef short T; + typedef test_allocator Alloc; + typedef std::list Cont; + typedef test_allocator ConvertibleToAlloc; + static_assert(std::uses_allocator_v && + !std::is_same_v); + + { + std::stack source; + std::stack stk(source, Alloc(2)); + static_assert(std::is_same_v>); + } + + { + std::stack source; + std::stack stk(source, ConvertibleToAlloc(2)); + static_assert(std::is_same_v>); + } + + { + std::stack source; + std::stack stk(std::move(source), Alloc(2)); + static_assert(std::is_same_v>); + } + + { + std::stack source; + std::stack stk(std::move(source), ConvertibleToAlloc(2)); + static_assert(std::is_same_v>); + } + } - return 0; + return 0; } diff --git a/libcxx/test/std/containers/sequences/deque/deque.cons/deduct.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.cons/deduct.pass.cpp --- a/libcxx/test/std/containers/sequences/deque/deque.cons/deduct.pass.cpp +++ b/libcxx/test/std/containers/sequences/deque/deque.cons/deduct.pass.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// +// // UNSUPPORTED: c++03, c++11, c++14 // UNSUPPORTED: libcpp-no-deduction-guides @@ -95,5 +95,34 @@ assert(deq.size() == 0); } - return 0; + { + typedef test_allocator Alloc; + typedef test_allocator ConvertibleToAlloc; + + { + std::deque source; + std::deque deq(source, Alloc(2)); + static_assert(std::is_same_v); + } + + { + std::deque source; + std::deque deq(source, ConvertibleToAlloc(2)); + static_assert(std::is_same_v); + } + + { + std::deque source; + std::deque deq(std::move(source), Alloc(2)); + static_assert(std::is_same_v); + } + + { + std::deque source; + std::deque deq(std::move(source), ConvertibleToAlloc(2)); + static_assert(std::is_same_v); + } + } + + return 0; } diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/deduct.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/deduct.pass.cpp --- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/deduct.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/deduct.pass.cpp @@ -12,8 +12,8 @@ // template ::value_type>> -// deque(InputIterator, InputIterator, Allocator = Allocator()) -// -> deque::value_type, Allocator>; +// forward_list(InputIterator, InputIterator, Allocator = Allocator()) +// -> forward_list::value_type, Allocator>; // @@ -100,5 +100,34 @@ assert(std::distance(fwl.begin(), fwl.end()) == 0); // no size for forward_list } - return 0; + { + typedef test_allocator Alloc; + typedef test_allocator ConvertibleToAlloc; + + { + std::forward_list source; + std::forward_list fwl(source, Alloc(2)); + static_assert(std::is_same_v); + } + + { + std::forward_list source; + std::forward_list fwl(source, ConvertibleToAlloc(2)); + static_assert(std::is_same_v); + } + + { + std::forward_list source; + std::forward_list fwl(std::move(source), Alloc(2)); + static_assert(std::is_same_v); + } + + { + std::forward_list source; + std::forward_list fwl(std::move(source), ConvertibleToAlloc(2)); + static_assert(std::is_same_v); + } + } + + return 0; } diff --git a/libcxx/test/std/containers/sequences/list/list.cons/deduct.pass.cpp b/libcxx/test/std/containers/sequences/list/list.cons/deduct.pass.cpp --- a/libcxx/test/std/containers/sequences/list/list.cons/deduct.pass.cpp +++ b/libcxx/test/std/containers/sequences/list/list.cons/deduct.pass.cpp @@ -100,5 +100,34 @@ assert(lst.size() == 0); } - return 0; + { + typedef test_allocator Alloc; + typedef test_allocator ConvertibleToAlloc; + + { + std::list source; + std::list lst(source, Alloc(2)); + static_assert(std::is_same_v); + } + + { + std::list source; + std::list lst(source, ConvertibleToAlloc(2)); + static_assert(std::is_same_v); + } + + { + std::list source; + std::list lst(std::move(source), Alloc(2)); + static_assert(std::is_same_v); + } + + { + std::list source; + std::list lst(std::move(source), ConvertibleToAlloc(2)); + static_assert(std::is_same_v); + } + } + + return 0; } diff --git a/libcxx/test/std/containers/sequences/vector/vector.cons/deduct.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.cons/deduct.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.cons/deduct.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.cons/deduct.pass.cpp @@ -12,8 +12,8 @@ // template ::value_type>> -// deque(InputIterator, InputIterator, Allocator = Allocator()) -// -> deque::value_type, Allocator>; +// vector(InputIterator, InputIterator, Allocator = Allocator()) +// -> vector::value_type, Allocator>; // @@ -113,5 +113,34 @@ assert(vec.size() == 0); } - return 0; + { + typedef test_allocator Alloc; + typedef test_allocator ConvertibleToAlloc; + + { + std::vector source; + std::vector vec(source, Alloc(2)); + static_assert(std::is_same_v); + } + + { + std::vector source; + std::vector vec(source, ConvertibleToAlloc(2)); + static_assert(std::is_same_v); + } + + { + std::vector source; + std::vector vec(std::move(source), Alloc(2)); + static_assert(std::is_same_v); + } + + { + std::vector source; + std::vector vec(std::move(source), ConvertibleToAlloc(2)); + static_assert(std::is_same_v); + } + } + + 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 --- 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 @@ -200,5 +200,24 @@ assert(m.get_allocator().get_id() == 48); } + { + // Examples from LWG3025 + std::unordered_map m{std::pair{1, 1}, {2, 2}, {3, 3}}; + ASSERT_SAME_TYPE(decltype(m), std::unordered_map); + + std::unordered_map m2{m.begin(), m.end()}; + ASSERT_SAME_TYPE(decltype(m2), std::unordered_map); + } + + { + // Examples from LWG3531 + std::unordered_map m1{{std::pair{1, 2}, {3, 4}}, 0}; + ASSERT_SAME_TYPE(decltype(m1), std::unordered_map); + + using value_type = std::pair; + std::unordered_map m2{{value_type{1, 2}, {3, 4}}, 0}; + ASSERT_SAME_TYPE(decltype(m2), 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 --- 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 @@ -200,5 +200,24 @@ assert(m.get_allocator().get_id() == 48); } + { + // Examples from LWG3025 + std::unordered_multimap m{std::pair{1, 1}, {2, 2}, {3, 3}}; + ASSERT_SAME_TYPE(decltype(m), std::unordered_multimap); + + std::unordered_multimap m2{m.begin(), m.end()}; + ASSERT_SAME_TYPE(decltype(m2), std::unordered_multimap); + } + + { + // Examples from LWG3531 + std::unordered_multimap m1{{std::pair{1, 2}, {3, 4}}, 0}; + ASSERT_SAME_TYPE(decltype(m1), std::unordered_multimap); + + using value_type = std::pair; + std::unordered_multimap m2{{value_type{1, 2}, {3, 4}}, 0}; + ASSERT_SAME_TYPE(decltype(m2), std::unordered_multimap); + } + return 0; }