diff --git a/libcxx/docs/Status/Cxx17.rst b/libcxx/docs/Status/Cxx17.rst --- a/libcxx/docs/Status/Cxx17.rst +++ b/libcxx/docs/Status/Cxx17.rst @@ -40,7 +40,6 @@ .. note:: - .. [#note-P0433] P0433: The only part not fully implemented is the requirement that certain deduction guides should not participate in overload resolution when given incorrect template arguments. .. [#note-P0607] P0607: The parts of P0607 that are not done are the ```` bits. diff --git a/libcxx/docs/Status/Cxx17Papers.csv b/libcxx/docs/Status/Cxx17Papers.csv --- a/libcxx/docs/Status/Cxx17Papers.csv +++ b/libcxx/docs/Status/Cxx17Papers.csv @@ -94,7 +94,7 @@ "`P0298R3 `__","CWG","A byte type definition","Kona","|Complete|","5.0" "`P0317R1 `__","LWG","Directory Entry Caching for Filesystem","Kona","|Complete|","7.0" "`P0430R2 `__","LWG","File system library on non-POSIX-like operating systems","Kona","|Complete|","7.0" -"`P0433R2 `__","LWG","Toward a resolution of US7 and US14: Integrating template deduction for class templates into the standard library","Kona","|In Progress| [#note-P0433]_","7.0" +"`P0433R2 `__","LWG","Toward a resolution of US7 and US14: Integrating template deduction for class templates into the standard library","Kona","|Complete|","14.0" "`P0452R1 `__","LWG","Unifying Parallel Algorithms","Kona","","" "`P0467R2 `__","LWG","Iterator Concerns for Parallel Algorithms","Kona","","" "`P0492R2 `__","LWG","Proposed Resolution of C++17 National Body Comments for Filesystems","Kona","|Complete|","7.0" diff --git a/libcxx/include/__memory/allocator_traits.h b/libcxx/include/__memory/allocator_traits.h --- a/libcxx/include/__memory/allocator_traits.h +++ b/libcxx/include/__memory/allocator_traits.h @@ -349,6 +349,14 @@ } }; +// A version of `allocator_traits` for internal usage that SFINAEs away if the +// given allocator doesn't have a nested `value_type`. This helps avoid hard +// errors when forming implicit deduction guides for a container that has an +// invalid Allocator type. See https://wg21.link/LWGXXXXX. +// TODO(varconst): use the actual link once available. +template +struct _LIBCPP_TEMPLATE_VIS __allocator_traits : allocator_traits<_Alloc> {}; + template struct __rebind_alloc_helper { #ifndef _LIBCPP_CXX03_LANG diff --git a/libcxx/include/deque b/libcxx/include/deque --- a/libcxx/include/deque +++ b/libcxx/include/deque @@ -129,7 +129,7 @@ template ::value_type>> deque(InputIterator, InputIterator, Allocator = Allocator()) - -> deque::value_type, Allocator>; + -> deque::value_type, Allocator>; // C++17 template bool operator==(const deque& x, const deque& y); @@ -162,6 +162,7 @@ #include <__config> #include <__debug> +#include <__iterator/iterator_traits.h> #include <__split_buffer> #include <__utility/forward.h> #include @@ -1258,20 +1259,20 @@ static_assert((is_same::value), "Allocator::value_type must be same type as value_type"); - typedef __deque_base __base; + typedef __deque_base __base; - typedef typename __base::__alloc_traits __alloc_traits; - typedef typename __base::reference reference; - typedef typename __base::const_reference const_reference; - typedef typename __base::iterator iterator; - typedef typename __base::const_iterator const_iterator; - typedef typename __base::size_type size_type; - typedef typename __base::difference_type difference_type; + typedef typename __base::__alloc_traits __alloc_traits; + typedef typename __base::reference reference; + typedef typename __base::const_reference const_reference; + typedef typename __base::iterator iterator; + typedef typename __base::const_iterator const_iterator; + typedef typename __allocator_traits::size_type size_type; + typedef typename __base::difference_type difference_type; - typedef typename __base::pointer pointer; - typedef typename __base::const_pointer const_pointer; - typedef _VSTD::reverse_iterator reverse_iterator; - typedef _VSTD::reverse_iterator const_reverse_iterator; + typedef typename __base::pointer pointer; + typedef typename __base::const_pointer const_pointer; + typedef _VSTD::reverse_iterator reverse_iterator; + typedef _VSTD::reverse_iterator const_reverse_iterator; using typename __base::__deque_range; using typename __base::__deque_block_range; @@ -1568,6 +1569,7 @@ #if _LIBCPP_STD_VER >= 17 template>, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>, class = enable_if_t<__is_allocator<_Alloc>::value> > deque(_InputIterator, _InputIterator) @@ -1575,13 +1577,13 @@ template::value>, class = enable_if_t<__is_allocator<_Alloc>::value> > deque(_InputIterator, _InputIterator, _Alloc) -> deque<__iter_value_type<_InputIterator>, _Alloc>; #endif - template deque<_Tp, _Allocator>::deque(size_type __n) { diff --git a/libcxx/include/forward_list b/libcxx/include/forward_list --- a/libcxx/include/forward_list +++ b/libcxx/include/forward_list @@ -647,7 +647,7 @@ typedef const value_type& const_reference; typedef typename allocator_traits::pointer pointer; typedef typename allocator_traits::const_pointer const_pointer; - typedef typename allocator_traits::size_type size_type; + typedef typename __allocator_traits::size_type size_type; typedef typename allocator_traits::difference_type difference_type; typedef typename base::iterator iterator; @@ -873,6 +873,7 @@ #if _LIBCPP_STD_VER >= 17 template>, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>, class = enable_if_t<__is_allocator<_Alloc>::value> > forward_list(_InputIterator, _InputIterator) @@ -880,6 +881,7 @@ template::value>, class = enable_if_t<__is_allocator<_Alloc>::value> > forward_list(_InputIterator, _InputIterator, _Alloc) diff --git a/libcxx/include/list b/libcxx/include/list --- a/libcxx/include/list +++ b/libcxx/include/list @@ -845,24 +845,24 @@ typedef typename base::__link_pointer __link_pointer; public: - typedef _Tp value_type; - typedef _Alloc allocator_type; + typedef _Tp value_type; + typedef _Alloc allocator_type; static_assert((is_same::value), "Invalid allocator::value_type"); - typedef value_type& reference; - typedef const value_type& const_reference; - typedef typename base::pointer pointer; - typedef typename base::const_pointer const_pointer; - typedef typename base::size_type size_type; - typedef typename base::difference_type difference_type; - typedef typename base::iterator iterator; - typedef typename base::const_iterator const_iterator; - typedef _VSTD::reverse_iterator reverse_iterator; - typedef _VSTD::reverse_iterator const_reverse_iterator; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef typename base::pointer pointer; + typedef typename base::const_pointer const_pointer; + typedef typename __allocator_traits::size_type size_type; + typedef typename base::difference_type difference_type; + typedef typename base::iterator iterator; + typedef typename base::const_iterator const_iterator; + typedef _VSTD::reverse_iterator reverse_iterator; + typedef _VSTD::reverse_iterator const_reverse_iterator; #if _LIBCPP_STD_VER > 17 - typedef size_type __remove_return_type; + typedef size_type __remove_return_type; #else - typedef void __remove_return_type; + typedef void __remove_return_type; #endif _LIBCPP_INLINE_VISIBILITY @@ -1144,6 +1144,7 @@ #if _LIBCPP_STD_VER >= 17 template>, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>, class = enable_if_t<__is_allocator<_Alloc>::value> > list(_InputIterator, _InputIterator) @@ -1151,6 +1152,7 @@ template::value>, class = enable_if_t<__is_allocator<_Alloc>::value> > list(_InputIterator, _InputIterator, _Alloc) diff --git a/libcxx/include/map b/libcxx/include/map --- a/libcxx/include/map +++ b/libcxx/include/map @@ -223,6 +223,25 @@ pair equal_range(const K& x) const; // C++14 }; +template >, + class Allocator = allocator>> +map(InputIterator, InputIterator, Compare = Compare(), Allocator = Allocator()) + -> map, iter_val_t, Compare, Allocator>; // C++17 + +template, + class Allocator = allocator>> +map(initializer_list>, Compare = Compare(), Allocator = Allocator()) + -> map; // C++17 + +template +map(InputIterator, InputIterator, Allocator) + -> map, iter_val_t, less>, + Allocator>; // C++17 + +template +map(initializer_list>, Allocator) -> map, Allocator>; // C++17 + template bool operator==(const map& x, @@ -444,6 +463,26 @@ pair equal_range(const K& x) const; // C++14 }; +template >, + class Allocator = allocator>> +multimap(InputIterator, InputIterator, Compare = Compare(), Allocator = Allocator()) + -> multimap, iter_val_t, Compare, Allocator>; // C++17 + +template, + class Allocator = allocator>> +multimap(initializer_list>, Compare = Compare(), Allocator = Allocator()) + -> multimap; // C++17 + +template +multimap(InputIterator, InputIterator, Allocator) + -> multimap, iter_val_t, + less>, Allocator>; // C++17 + +template +multimap(initializer_list>, Allocator) + -> multimap, Allocator>; // C++17 + template bool operator==(const multimap& x, @@ -492,6 +531,7 @@ #include <__config> #include <__debug> #include <__functional/is_transparent.h> +#include <__iterator/iterator_traits.h> #include <__node_handle> #include <__tree> #include <__utility/forward.h> @@ -1501,6 +1541,7 @@ #if _LIBCPP_STD_VER >= 17 template>, class _Allocator = allocator<__iter_to_alloc_type<_InputIterator>>, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value, void>, class = enable_if_t::value, void>, class = enable_if_t<__is_allocator<_Allocator>::value, void>> map(_InputIterator, _InputIterator, _Compare = _Compare(), _Allocator = _Allocator()) @@ -1514,6 +1555,7 @@ -> map, _Tp, _Compare, _Allocator>; template::value, void>, class = enable_if_t<__is_allocator<_Allocator>::value, void>> map(_InputIterator, _InputIterator, _Allocator) -> map<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>, @@ -2174,6 +2216,7 @@ #if _LIBCPP_STD_VER >= 17 template>, class _Allocator = allocator<__iter_to_alloc_type<_InputIterator>>, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value, void>, class = enable_if_t::value, void>, class = enable_if_t<__is_allocator<_Allocator>::value, void>> multimap(_InputIterator, _InputIterator, _Compare = _Compare(), _Allocator = _Allocator()) @@ -2187,6 +2230,7 @@ -> multimap, _Tp, _Compare, _Allocator>; template::value, void>, class = enable_if_t<__is_allocator<_Allocator>::value, void>> multimap(_InputIterator, _InputIterator, _Allocator) -> multimap<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>, diff --git a/libcxx/include/queue b/libcxx/include/queue --- a/libcxx/include/queue +++ b/libcxx/include/queue @@ -185,16 +185,16 @@ priority_queue(InputIterator, InputIterator, Allocator) -> priority_queue, vector, Allocator>, - less>>; + less>>; // C++17 template priority_queue(InputIterator, InputIterator, Compare, Allocator) -> priority_queue, - vector, Allocator>, Compare>; + vector, Allocator>, Compare>; // C++17 template priority_queue(InputIterator, InputIterator, Compare, Container, Allocator) - -> priority_queue; + -> priority_queue; // C++17 template void swap(priority_queue& x, diff --git a/libcxx/include/set b/libcxx/include/set --- a/libcxx/include/set +++ b/libcxx/include/set @@ -183,6 +183,25 @@ pair equal_range(const K& x) const; // C++14 }; +template ::value_type>, + class Allocator = allocator::value_type>> +set(InputIterator, InputIterator, + Compare = Compare(), Allocator = Allocator()) + -> set::value_type, Compare, Allocator>; // C++17 + +template, class Allocator = allocator> +set(initializer_list, Compare = Compare(), Allocator = Allocator()) + -> set; // C++17 + +template +set(InputIterator, InputIterator, Allocator) + -> set::value_type, + less::value_type>, Allocator>; // C++17 + +template +set(initializer_list, Allocator) -> set, Allocator>; // C++17 + template bool operator==(const set& x, @@ -389,6 +408,25 @@ pair equal_range(const K& x) const; // C++14 }; +template ::value_type>, + class Allocator = allocator::value_type>> +multiset(InputIterator, InputIterator, + Compare = Compare(), Allocator = Allocator()) + -> multiset::value_type, Compare, Allocator>; // C++17 + +template, class Allocator = allocator> +multiset(initializer_list, Compare = Compare(), Allocator = Allocator()) + -> multiset; // C++17 + +template +multiset(InputIterator, InputIterator, Allocator) + -> multiset::value_type, + less::value_type>, Allocator>; // C++17 + +template +multiset(initializer_list, Allocator) -> multiset, Allocator>; // C++17 + template bool operator==(const multiset& x, @@ -436,6 +474,7 @@ #include <__config> #include <__debug> #include <__functional/is_transparent.h> +#include <__iterator/iterator_traits.h> #include <__node_handle> #include <__tree> #include <__utility/forward.h> @@ -462,7 +501,7 @@ // types: typedef _Key key_type; typedef key_type value_type; - typedef _Compare key_compare; + typedef __identity_t<_Compare> key_compare; typedef key_compare value_compare; typedef __identity_t<_Allocator> allocator_type; typedef value_type& reference; @@ -474,7 +513,6 @@ private: typedef __tree __base; typedef allocator_traits __alloc_traits; - typedef typename __base::__node_holder __node_holder; __base __tree_; @@ -872,6 +910,7 @@ template>, class _Allocator = allocator<__iter_value_type<_InputIterator>>, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value, void>, class = enable_if_t<__is_allocator<_Allocator>::value, void>, class = enable_if_t::value, void>> set(_InputIterator, _InputIterator, _Compare = _Compare(), _Allocator = _Allocator()) @@ -879,12 +918,13 @@ template, class _Allocator = allocator<_Key>, - class = enable_if_t<__is_allocator<_Allocator>::value, void>, - class = enable_if_t::value, void>> + class = enable_if_t::value, void>, + class = enable_if_t<__is_allocator<_Allocator>::value, void>> set(initializer_list<_Key>, _Compare = _Compare(), _Allocator = _Allocator()) -> set<_Key, _Compare, _Allocator>; template::value, void>, class = enable_if_t<__is_allocator<_Allocator>::value, void>> set(_InputIterator, _InputIterator, _Allocator) -> set<__iter_value_type<_InputIterator>, @@ -994,7 +1034,7 @@ // types: typedef _Key key_type; typedef key_type value_type; - typedef _Compare key_compare; + typedef __identity_t<_Compare> key_compare; typedef key_compare value_compare; typedef __identity_t<_Allocator> allocator_type; typedef value_type& reference; @@ -1006,7 +1046,6 @@ private: typedef __tree __base; typedef allocator_traits __alloc_traits; - typedef typename __base::__node_holder __node_holder; __base __tree_; @@ -1403,6 +1442,7 @@ template>, class _Allocator = allocator<__iter_value_type<_InputIterator>>, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value, void>, class = enable_if_t<__is_allocator<_Allocator>::value, void>, class = enable_if_t::value, void>> multiset(_InputIterator, _InputIterator, _Compare = _Compare(), _Allocator = _Allocator()) @@ -1416,6 +1456,7 @@ -> multiset<_Key, _Compare, _Allocator>; template::value, void>, class = enable_if_t<__is_allocator<_Allocator>::value, void>> multiset(_InputIterator, _InputIterator, _Allocator) -> multiset<__iter_value_type<_InputIterator>, diff --git a/libcxx/include/unordered_map b/libcxx/include/unordered_map --- a/libcxx/include/unordered_map +++ b/libcxx/include/unordered_map @@ -216,6 +216,47 @@ void reserve(size_type n); }; +template>, class Pred = equal_to>, + class Allocator = allocator>> +unordered_map(InputIterator, InputIterator, typename see below::size_type = see below, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_map, iter_value_t, Hash, Pred, + Allocator>; // C++17 + +template, + class Pred = equal_to, class Allocator = allocator>> +unordered_map(initializer_list>, typename see below::size_type = see below, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_map; // C++17 + +template +unordered_map(InputIterator, InputIterator, typename see below::size_type, Allocator) + -> unordered_map, iter_val_t, + hash>, equal_to>, Allocator>; // C++17 + +template +unordered_map(InputIterator, InputIterator, Allocator) + -> unordered_map, iter_val_t, + hash>, equal_to>, Allocator>; // C++17 + +template +unordered_map(InputIterator, InputIterator, typename see below::size_type, Hash, Allocator) + -> unordered_map, iter_val_t, Hash, + equal_to>, Allocator>; // C++17 + +template +unordered_map(initializer_list>, typename see below::size_type, Allocator) + -> unordered_map, equal_to, Allocator>; // C++17 + +template +unordered_map(initializer_list>, Allocator) + -> unordered_map, equal_to, Allocator>; // C++17 + +template +unordered_map(initializer_list>, typename see below::size_type, Hash, Allocator) + -> unordered_map, Allocator>; // C++17 + template void swap(unordered_map& x, unordered_map& y) @@ -404,6 +445,48 @@ void reserve(size_type n); }; +template>, class Pred = equal_to>, + class Allocator = allocator>> +unordered_multimap(InputIterator, InputIterator, typename see below::size_type = see below, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_multimap, iter_value_t, Hash, Pred, + Allocator>; // C++17 + +template, + class Pred = equal_to, class Allocator = allocator>> +unordered_multimap(initializer_list>, typename see below::size_type = see below, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_multimap; // C++17 + +template +unordered_multimap(InputIterator, InputIterator, typename see below::size_type, Allocator) + -> unordered_multimap, iter_val_t, + hash>, equal_to>, Allocator>; // C++17 + +template +unordered_multimap(InputIterator, InputIterator, Allocator) + -> unordered_multimap, iter_val_t, + hash>, equal_to>, Allocator>; // C++17 + +template +unordered_multimap(InputIterator, InputIterator, typename see below::size_type, Hash, Allocator) + -> unordered_multimap, iter_val_t, Hash, + equal_to>, Allocator>; // C++17 + +template +unordered_multimap(initializer_list>, typename see below::size_type, Allocator) + -> unordered_multimap, equal_to, Allocator>; // C++17 + +template +unordered_multimap(initializer_list>, Allocator) + -> unordered_multimap, equal_to, Allocator>; // C++17 + +template +unordered_multimap(initializer_list>, typename see below::size_type, Hash, + Allocator) + -> unordered_multimap, Allocator>; // C++17 + template void swap(unordered_multimap& x, unordered_multimap& y) @@ -434,6 +517,7 @@ #include <__config> #include <__debug> #include <__functional/is_transparent.h> +#include <__iterator/iterator_traits.h> #include <__hash_table> #include <__node_handle> #include <__utility/forward.h> @@ -1470,6 +1554,7 @@ class _Hash = hash<__iter_key_type<_InputIterator>>, class _Pred = equal_to<__iter_key_type<_InputIterator>>, class _Allocator = allocator<__iter_to_alloc_type<_InputIterator>>, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>, class = enable_if_t::value>, class = enable_if_t::value>, class = enable_if_t::value>, @@ -1490,18 +1575,21 @@ -> unordered_map, _Tp, _Hash, _Pred, _Allocator>; template::value>, class = enable_if_t<__is_allocator<_Allocator>::value>> unordered_map(_InputIterator, _InputIterator, typename allocator_traits<_Allocator>::size_type, _Allocator) -> unordered_map<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>, hash<__iter_key_type<_InputIterator>>, equal_to<__iter_key_type<_InputIterator>>, _Allocator>; template::value>, class = enable_if_t<__is_allocator<_Allocator>::value>> unordered_map(_InputIterator, _InputIterator, _Allocator) -> unordered_map<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>, hash<__iter_key_type<_InputIterator>>, equal_to<__iter_key_type<_InputIterator>>, _Allocator>; template::value>, class = enable_if_t::value>, class = enable_if_t::value>, class = enable_if_t<__is_allocator<_Allocator>::value>> @@ -2268,6 +2356,7 @@ class _Hash = hash<__iter_key_type<_InputIterator>>, class _Pred = equal_to<__iter_key_type<_InputIterator>>, class _Allocator = allocator<__iter_to_alloc_type<_InputIterator>>, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>, class = enable_if_t::value>, class = enable_if_t::value>, class = enable_if_t::value>, @@ -2288,18 +2377,21 @@ -> unordered_multimap, _Tp, _Hash, _Pred, _Allocator>; template::value>, class = enable_if_t<__is_allocator<_Allocator>::value>> unordered_multimap(_InputIterator, _InputIterator, typename allocator_traits<_Allocator>::size_type, _Allocator) -> unordered_multimap<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>, hash<__iter_key_type<_InputIterator>>, equal_to<__iter_key_type<_InputIterator>>, _Allocator>; template::value>, class = enable_if_t<__is_allocator<_Allocator>::value>> unordered_multimap(_InputIterator, _InputIterator, _Allocator) -> unordered_multimap<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>, hash<__iter_key_type<_InputIterator>>, equal_to<__iter_key_type<_InputIterator>>, _Allocator>; template::value>, class = enable_if_t::value>, class = enable_if_t::value>, class = enable_if_t<__is_allocator<_Allocator>::value>> diff --git a/libcxx/include/unordered_set b/libcxx/include/unordered_set --- a/libcxx/include/unordered_set +++ b/libcxx/include/unordered_set @@ -182,6 +182,43 @@ void reserve(size_type n); }; +template::value_type>, + class Pred = equal_to::value_type>, + class Allocator = allocator::value_type>> +unordered_set(InputIterator, InputIterator, typename see below::size_type = see below, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_set::value_type, + Hash, Pred, Allocator>; // C++17 + +template, + class Pred = equal_to, class Allocator = allocator> +unordered_set(initializer_list, typename see below::size_type = see below, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_set; // C++17 + +template +unordered_set(InputIterator, InputIterator, typename see below::size_type, Allocator) + -> unordered_set::value_type, + hash::value_type>, + equal_to::value_type>, + Allocator>; // C++17 + +template +unordered_set(InputIterator, InputIterator, typename see below::size_type, + Hash, Allocator) + -> unordered_set::value_type, Hash, + equal_to::value_type>, + Allocator>; // C++17 + +template +unordered_set(initializer_list, typename see below::size_type, Allocator) + -> unordered_set, equal_to, Allocator>; // C++17 + +template +unordered_set(initializer_list, typename see below::size_type, Hash, Allocator) + -> unordered_set, Allocator>; // C++17 + template void swap(unordered_set& x, unordered_set& y) @@ -359,6 +396,42 @@ void reserve(size_type n); }; +template::value_type>, + class Pred = equal_to::value_type>, + class Allocator = allocator::value_type>> +unordered_multiset(InputIterator, InputIterator, see below::size_type = see below, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_multiset::value_type, + Hash, Pred, Allocator>; // C++17 + +template, + class Pred = equal_to, class Allocator = allocator> +unordered_multiset(initializer_list, typename see below::size_type = see below, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_multiset; // C++17 + +template +unordered_multiset(InputIterator, InputIterator, typename see below::size_type, Allocator) + -> unordered_multiset::value_type, + hash::value_type>, + equal_to::value_type>, + Allocator>; // C++17 + +template +unordered_multiset(InputIterator, InputIterator, typename see below::size_type, + Hash, Allocator) + -> unordered_multiset::value_type, Hash, + equal_to::value_type>, Allocator>; // C++17 + +template +unordered_multiset(initializer_list, typename see below::size_type, Allocator) + -> unordered_multiset, equal_to, Allocator>; // C++17 + +template +unordered_multiset(initializer_list, typename see below::size_type, Hash, Allocator) + -> unordered_multiset, Allocator>; // C++17 + template void swap(unordered_multiset& x, unordered_multiset& y) @@ -803,6 +876,7 @@ class _Hash = hash<__iter_value_type<_InputIterator>>, class _Pred = equal_to<__iter_value_type<_InputIterator>>, class _Allocator = allocator<__iter_value_type<_InputIterator>>, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>, class = enable_if_t::value>, class = enable_if_t::value>, class = enable_if_t::value>, @@ -823,6 +897,7 @@ -> unordered_set<_Tp, _Hash, _Pred, _Allocator>; template::value>, class = enable_if_t<__is_allocator<_Allocator>::value>> unordered_set(_InputIterator, _InputIterator, typename allocator_traits<_Allocator>::size_type, _Allocator) @@ -832,6 +907,7 @@ _Allocator>; template::value>, class = enable_if_t::value>, class = enable_if_t::value>, class = enable_if_t<__is_allocator<_Allocator>::value>> @@ -1468,6 +1544,7 @@ class _Hash = hash<__iter_value_type<_InputIterator>>, class _Pred = equal_to<__iter_value_type<_InputIterator>>, class _Allocator = allocator<__iter_value_type<_InputIterator>>, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>, class = enable_if_t::value>, class = enable_if_t::value>, class = enable_if_t::value>, @@ -1487,6 +1564,7 @@ -> unordered_multiset<_Tp, _Hash, _Pred, _Allocator>; template::value>, class = enable_if_t<__is_allocator<_Allocator>::value>> unordered_multiset(_InputIterator, _InputIterator, typename allocator_traits<_Allocator>::size_type, _Allocator) -> unordered_multiset<__iter_value_type<_InputIterator>, @@ -1495,6 +1573,7 @@ _Allocator>; template::value>, class = enable_if_t::value>, class = enable_if_t::value>, class = enable_if_t<__is_allocator<_Allocator>::value>> diff --git a/libcxx/include/vector b/libcxx/include/vector --- a/libcxx/include/vector +++ b/libcxx/include/vector @@ -245,7 +245,7 @@ template ::value_type>> vector(InputIterator, InputIterator, Allocator = Allocator()) - -> vector::value_type, Allocator>; + -> vector::value_type, Allocator>; // C++17 template struct hash>; @@ -275,6 +275,7 @@ #include <__bit_reference> #include <__debug> #include <__functional_base> +#include <__iterator/iterator_traits.h> #include <__iterator/wrap_iter.h> #include <__split_buffer> #include <__utility/forward.h> @@ -898,6 +899,7 @@ #if _LIBCPP_STD_VER >= 17 template>, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>, class = enable_if_t<__is_allocator<_Alloc>::value> > vector(_InputIterator, _InputIterator) @@ -905,6 +907,7 @@ template::value>, class = enable_if_t<__is_allocator<_Alloc>::value> > vector(_InputIterator, _InputIterator, _Alloc) 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 @@ -32,6 +32,7 @@ #include #include +#include "deduction_guides_sfinae_checks.h" #include "test_allocator.h" using P = std::pair; @@ -151,5 +152,7 @@ ASSERT_SAME_TYPE(decltype(m2), std::map); } + AssociativeContainerDeductionGuidesSfinaeAway>(); + 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 @@ -32,6 +32,7 @@ #include #include +#include "deduction_guides_sfinae_checks.h" #include "test_allocator.h" using P = std::pair; @@ -151,5 +152,7 @@ ASSERT_SAME_TYPE(decltype(m2), std::multimap); } + AssociativeContainerDeductionGuidesSfinaeAway>(); + return 0; } diff --git a/libcxx/test/std/containers/associative/multiset/multiset.cons/deduct.pass.cpp b/libcxx/test/std/containers/associative/multiset/multiset.cons/deduct.pass.cpp --- a/libcxx/test/std/containers/associative/multiset/multiset.cons/deduct.pass.cpp +++ b/libcxx/test/std/containers/associative/multiset/multiset.cons/deduct.pass.cpp @@ -35,6 +35,7 @@ #include #include +#include "deduction_guides_sfinae_checks.h" #include "test_allocator.h" struct NotAnAllocator { @@ -186,5 +187,7 @@ assert(s.size() == 2); } + AssociativeContainerDeductionGuidesSfinaeAway>(); + return 0; } diff --git a/libcxx/test/std/containers/associative/set/set.cons/deduct.pass.cpp b/libcxx/test/std/containers/associative/set/set.cons/deduct.pass.cpp --- a/libcxx/test/std/containers/associative/set/set.cons/deduct.pass.cpp +++ b/libcxx/test/std/containers/associative/set/set.cons/deduct.pass.cpp @@ -35,6 +35,7 @@ #include #include +#include "deduction_guides_sfinae_checks.h" #include "test_allocator.h" struct NotAnAllocator { @@ -184,5 +185,7 @@ assert(s.size() == 2); } + AssociativeContainerDeductionGuidesSfinaeAway>(); + 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 @@ -31,6 +31,7 @@ #include #include // INT_MAX +#include "deduction_guides_sfinae_checks.h" #include "test_macros.h" #include "test_iterators.h" #include "test_allocator.h" @@ -239,5 +240,121 @@ } } + // Deduction guides should be SFINAE'd away when given: + // - "bad" input iterators (that is, a type not qualifying as an input + // iterator); + // - a bad allocator; + // - an allocator instead of a comparator; + // - an allocator instead of a container; + // - an allocator and a container that uses a different allocator. + { + using Comp = std::less; + using Cont = std::vector; + using Alloc = std::allocator; + using Iter = int*; + + // The only requirement in the Standard is that integral types cannot be + // considered input iterators, beyond that it is unspecified. + using BadIter = int; +#ifdef _LIBCPP_VERSION + struct OutputIter { + using iterator_category = std::output_iterator_tag; + using value_type = void; + using difference_type = void; + using pointer = void; + using reference = void; + + const OutputIter& operator*() const { return *this; } + const OutputIter& operator++() { return *this; } + OutputIter operator++(int) const { return *this; } + }; +#endif // _LIBCPP_VERSION + + struct BadAlloc {}; + using AllocAsComp = Alloc; + using AllocAsCont = Alloc; + using DiffAlloc = test_allocator; + + // (iter, iter) + // + // Cannot deduce from (BAD_iter, BAD_iter) + static_assert(SFINAEs_away); + // Note: (OutputIter, OutputIter) is interpreted as (comp, cont) and fails on accessing + // non-existent typedefs in `OutputIter` (as if it were a container). There is no + // requirement to SFINAE away bad containers. + + // (iter, iter, comp) + // + // Cannot deduce from (BAD_iter, BAD_iter, comp) + static_assert(SFINAEs_away); + LIBCPP_STATIC_ASSERT(SFINAEs_away); + // Note: (iter, iter, ALLOC_as_comp) is allowed -- it just calls (iter, iter, alloc). + + // (iter, iter, comp, cont) + // + // Cannot deduce from (BAD_iter, BAD_iter, comp, cont) + static_assert(SFINAEs_away); + LIBCPP_STATIC_ASSERT(SFINAEs_away); + // Cannot deduce from (iter, iter, ALLOC_as_comp, cont) + static_assert(SFINAEs_away); + // Note: (iter, iter, comp, ALLOC_as_cont) is allowed -- it just calls (iter, iter, comp, + // alloc). + + // (iter, iter, alloc) + // + // Cannot deduce from (BAD_iter, BAD_iter, alloc) + static_assert(SFINAEs_away); + LIBCPP_STATIC_ASSERT(SFINAEs_away); + // Note: (iter, iter, BAD_alloc) is interpreted as (iter, iter, comp) instead and fails upon + // instantiation. There is no requirement to SFINAE away bad comparators. + + // (iter, iter, comp, alloc) + // + // Cannot deduce from (iter, iter, ALLOC_as_comp, alloc) + static_assert(SFINAEs_away); + // Note: (iter, iter, comp, BAD_alloc) is interpreted as (iter, iter, comp, cont) instead + // and fails upon instantiation. There is no requirement to SFINAE away bad containers. + + // (iter, iter, comp, cont, alloc) + // + // Cannot deduce from (BAD_iter, BAD_iter, comp, cont, alloc) + static_assert(SFINAEs_away); + LIBCPP_STATIC_ASSERT( + SFINAEs_away); + // Cannot deduce from (iter, iter, ALLOC_as_comp, cont, alloc) + static_assert(SFINAEs_away); + // Cannot deduce from (iter, iter, comp, ALLOC_as_cont, alloc) + static_assert(SFINAEs_away); + // Cannot deduce from (iter, iter, comp, cont, BAD_alloc) + static_assert(SFINAEs_away); + // Cannot deduce from (iter, iter, comp, cont, DIFFERENT_alloc) + static_assert(SFINAEs_away); + + // (comp, alloc) + // + // Cannot deduce from (ALLOC_as_comp, alloc) + static_assert(SFINAEs_away); + // Cannot deduce from (comp, BAD_alloc) + static_assert(SFINAEs_away); + + // (comp, cont, alloc) + // + // Cannot deduce from (ALLOC_as_comp, cont, alloc) + static_assert(SFINAEs_away); + // Cannot deduce from (comp, ALLOC_as_cont, alloc) + static_assert(SFINAEs_away); + // Cannot deduce from (comp, cont, BAD_alloc) + static_assert(SFINAEs_away); + // Cannot deduce from (comp, cont, DIFFERENT_alloc) + static_assert(SFINAEs_away); + + // (comp, cont) + // + // Cannot deduce from (ALLOC_as_comp, cont) + static_assert(SFINAEs_away); + // Cannot deduce from (comp, ALLOC_as_cont) + static_assert(SFINAEs_away); + } + 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 @@ -21,8 +21,8 @@ #include #include #include -#include // INT_MAX +#include "deduction_guides_sfinae_checks.h" #include "test_macros.h" #include "test_iterators.h" #include "test_allocator.h" @@ -133,5 +133,27 @@ } } + // Deduction guides should be SFINAE'd away when given: + // - a "bad" allocator (that is, a type not qualifying as an allocator); + // - an allocator instead of a container; + // - an allocator and a container that uses a different allocator. + { + using Cont = std::list; + using Alloc = std::allocator; + using DiffAlloc = test_allocator; + + struct BadAlloc {}; + using AllocAsCont = Alloc; + + // (cont, alloc) + // + // Cannot deduce from (ALLOC_as_cont, alloc) + static_assert(SFINAEs_away); + // Cannot deduce from (cont, BAD_alloc) + static_assert(SFINAEs_away); + // Cannot deduce from (cont, DIFFERENT_alloc) + static_assert(SFINAEs_away); + } + 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 @@ -25,6 +25,7 @@ #include #include // INT_MAX +#include "deduction_guides_sfinae_checks.h" #include "test_macros.h" #include "test_iterators.h" #include "test_allocator.h" @@ -136,5 +137,27 @@ } } + // Deduction guides should be SFINAE'd away when given: + // - a "bad" allocator (that is, a type not qualifying as an allocator); + // - an allocator instead of a container; + // - an allocator and a container that uses a different allocator. + { + using Cont = std::list; + using Alloc = std::allocator; + using DiffAlloc = test_allocator; + + struct BadAlloc {}; + using AllocAsCont = Alloc; + + // (cont, alloc) + // + // Cannot deduce from (ALLOC_as_cont, alloc) + static_assert(SFINAEs_away); + // Cannot deduce from (cont, BAD_alloc) + static_assert(SFINAEs_away); + // Cannot deduce from (cont, DIFFERENT_alloc) + static_assert(SFINAEs_away); + } + 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 @@ -20,6 +20,7 @@ #include #include // INT_MAX +#include "deduction_guides_sfinae_checks.h" #include "test_macros.h" #include "test_iterators.h" #include "test_allocator.h" @@ -121,5 +122,7 @@ } } + SequenceContainerDeductionGuidesSfinaeAway>(); + 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 @@ -20,6 +20,7 @@ #include #include // INT_MAX +#include "deduction_guides_sfinae_checks.h" #include "test_macros.h" #include "test_iterators.h" #include "test_allocator.h" @@ -126,5 +127,7 @@ } } + SequenceContainerDeductionGuidesSfinaeAway>(); + 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 @@ -20,6 +20,7 @@ #include #include // INT_MAX +#include "deduction_guides_sfinae_checks.h" #include "test_macros.h" #include "test_iterators.h" #include "test_allocator.h" @@ -126,5 +127,7 @@ } } + SequenceContainerDeductionGuidesSfinaeAway>(); + 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 @@ -15,11 +15,13 @@ // #include -#include #include #include #include // INT_MAX +#include +#include +#include "deduction_guides_sfinae_checks.h" #include "test_macros.h" #include "test_iterators.h" #include "test_allocator.h" @@ -139,5 +141,7 @@ } } + SequenceContainerDeductionGuidesSfinaeAway>(); + 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 @@ -61,6 +61,7 @@ #include #include +#include "deduction_guides_sfinae_checks.h" #include "test_allocator.h" using P = std::pair; @@ -218,5 +219,7 @@ ASSERT_SAME_TYPE(decltype(m2), std::unordered_map); } + UnorderedContainerDeductionGuidesSfinaeAway>(); + 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 @@ -61,6 +61,7 @@ #include #include +#include "deduction_guides_sfinae_checks.h" #include "test_allocator.h" using P = std::pair; @@ -218,5 +219,7 @@ ASSERT_SAME_TYPE(decltype(m2), std::unordered_multimap); } + UnorderedContainerDeductionGuidesSfinaeAway>(); + return 0; } diff --git a/libcxx/test/std/containers/unord/unord.multiset/unord.multiset.cnstr/deduct.pass.cpp b/libcxx/test/std/containers/unord/unord.multiset/unord.multiset.cnstr/deduct.pass.cpp --- a/libcxx/test/std/containers/unord/unord.multiset/unord.multiset.cnstr/deduct.pass.cpp +++ b/libcxx/test/std/containers/unord/unord.multiset/unord.multiset.cnstr/deduct.pass.cpp @@ -53,6 +53,7 @@ #include #include +#include "deduction_guides_sfinae_checks.h" #include "test_allocator.h" int main(int, char**) @@ -192,5 +193,7 @@ assert(s.get_allocator().get_id() == 42); } + UnorderedContainerDeductionGuidesSfinaeAway>(); + return 0; } diff --git a/libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/deduct.pass.cpp b/libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/deduct.pass.cpp --- a/libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/deduct.pass.cpp +++ b/libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/deduct.pass.cpp @@ -53,6 +53,7 @@ #include #include +#include "deduction_guides_sfinae_checks.h" #include "test_allocator.h" int main(int, char**) @@ -192,5 +193,7 @@ assert(s.get_allocator().get_id() == 42); } + UnorderedContainerDeductionGuidesSfinaeAway>(); + return 0; } diff --git a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/deduct.pass.cpp b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/deduct.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/deduct.pass.cpp @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14 + +// + +// unique_ptr + +// The following constructors should not be selected by class template argument +// deduction: +// +// explicit unique_ptr(pointer p) +// unique_ptr(pointer p, const D& d) noexcept +// unique_ptr(pointer p, remove_reference_t&& d) noexcept + +#include + +#include "deduction_guides_sfinae_checks.h" + +struct Deleter { + void operator()(int* p) const { delete p; } +}; + +int main(int, char**) { + // Cannot deduce from (ptr). + static_assert(SFINAEs_away); + // Cannot deduce from (array). + static_assert(SFINAEs_away); + // Cannot deduce from (ptr, Deleter&&). + static_assert(SFINAEs_away); + // Cannot deduce from (array, Deleter&&). + static_assert(SFINAEs_away); + // Cannot deduce from (ptr, const Deleter&). + static_assert(SFINAEs_away); + // Cannot deduce from (array, const Deleter&). + static_assert(SFINAEs_away); + + return 0; +} diff --git a/libcxx/test/support/deduction_guides_sfinae_checks.h b/libcxx/test/support/deduction_guides_sfinae_checks.h new file mode 100644 --- /dev/null +++ b/libcxx/test/support/deduction_guides_sfinae_checks.h @@ -0,0 +1,309 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef TEST_SUPPORT_DEDUCTION_GUIDES_SFINAE_CHECKS_H +#define TEST_SUPPORT_DEDUCTION_GUIDES_SFINAE_CHECKS_H + +#include +#include +#include +#include + +#include "test_macros.h" + +// `SFINAEs_away` template variable checks whether the template arguments for +// a given template class `Instantiated` can be deduced from the given +// constructor parameter types `CtrArgs` using CTAD. + +template class Instantiated, class ...CtrArgs, + class = decltype(Instantiated(std::declval()...))> +std::false_type SFINAEs_away_impl(int); + +template class Instantiated, class ...CtrArgs> +std::true_type SFINAEs_away_impl(...); + +template class Instantiated, class ...CtrArgs> +constexpr bool SFINAEs_away = + decltype(SFINAEs_away_impl(0))::value; + +// For sequence containers the deduction guides should be SFINAE'd away when +// given: +// - "bad" input iterators (that is, a type not qualifying as an input +// iterator); +// - a bad allocator. +template class Container, typename InstantiatedContainer> +constexpr void SequenceContainerDeductionGuidesSfinaeAway() { + using Alloc = std::allocator; + using Iter = int*; + + struct BadAlloc {}; + // Note: the only requirement in the Standard is that integral types cannot be + // considered input iterators; however, this doesn't work for sequence + // containers because they have constructors of the form `(size_type count, + // const value_type& value)`. These constructors would be used when passing + // two integral types and would deduce `value_type` to be an integral type. +#ifdef _LIBCPP_VERSION + using OutputIter = std::insert_iterator; +#endif // _LIBCPP_VERSION + + // (iter, iter) + // + // Cannot deduce from (BAD_iter, BAD_iter) + LIBCPP_STATIC_ASSERT(SFINAEs_away); + + // (iter, iter, alloc) + // + // Cannot deduce from (BAD_iter, BAD_iter, alloc) + LIBCPP_STATIC_ASSERT(SFINAEs_away); + // Cannot deduce from (iter, iter, BAD_alloc) + static_assert(SFINAEs_away); + + // (alloc) + // + // Cannot deduce from (alloc) + static_assert(SFINAEs_away); +} + +// For associative containers the deduction guides should be SFINAE'd away when +// given: +// - "bad" input iterators (that is, a type not qualifying as an input +// iterator); +// - a bad allocator; +// - an allocator in place of a comparator. + +template class Container, typename InstantiatedContainer> +constexpr void AssociativeContainerDeductionGuidesSfinaeAway() { + using ValueType = typename InstantiatedContainer::value_type; + using Comp = std::less; + using Alloc = std::allocator; + using Iter = ValueType*; + using InitList = std::initializer_list; + + struct BadAlloc {}; + // The only requirement in the Standard is that integral types cannot be + // considered input iterators, beyond that it is unspecified. + using BadIter = int; +#ifdef _LIBCPP_VERSION + using OutputIter = std::insert_iterator; +#endif // _LIBCPP_VERSION + using AllocAsComp = Alloc; + + // (iter, iter) + // + // Cannot deduce from (BAD_iter, BAD_iter) + static_assert(SFINAEs_away); + LIBCPP_STATIC_ASSERT(SFINAEs_away); + + // (iter, iter, comp) + // + // Cannot deduce from (BAD_iter, BAD_iter, comp) + static_assert(SFINAEs_away); + LIBCPP_STATIC_ASSERT(SFINAEs_away); + + // (iter, iter, comp, alloc) + // + // Cannot deduce from (BAD_iter, BAD_iter, comp, alloc) + static_assert(SFINAEs_away); + LIBCPP_STATIC_ASSERT( + SFINAEs_away); + // Cannot deduce from (iter, iter, ALLOC_as_comp, alloc) + static_assert(SFINAEs_away); + // Cannot deduce from (iter, iter, comp, BAD_alloc) + static_assert(SFINAEs_away); + + // (iter, iter, alloc) + // + // Cannot deduce from (BAD_iter, BAD_iter, alloc) + static_assert(SFINAEs_away); + LIBCPP_STATIC_ASSERT(SFINAEs_away); + // Note: (iter, iter, BAD_alloc) is interpreted as (iter, iter, comp) + // instead and fails upon instantiation. There is no requirement to SFINAE + // away bad comparators. + + // (init_list, comp, alloc) + // + // Cannot deduce from (init_list, ALLOC_as_comp, alloc) + static_assert(SFINAEs_away); + // Cannot deduce from (init_list, comp, BAD_alloc) + static_assert(SFINAEs_away); + + // (init_list, alloc) + // + // Note: (init_list, BAD_alloc) is interpreted as (init_list, comp) instead + // and fails upon instantiation. There is no requirement to SFINAE away bad + // comparators. +} + +// For unordered containers the deduction guides should be SFINAE'd away when +// given: +// - "bad" input iterators (that is, a type not qualifying as an input +// iterator); +// - a bad allocator; +// - a bad hash functor (an integral type in place of a hash); +// - an allocator in place of a hash functor; +// - an allocator in place of a predicate. +template class Container, typename InstantiatedContainer> +constexpr void UnorderedContainerDeductionGuidesSfinaeAway() { + using ValueType = typename InstantiatedContainer::value_type; + using Pred = std::equal_to; + using Hash = std::hash; + using Alloc = std::allocator; + using Iter = ValueType*; + using InitList = std::initializer_list; + + using BadHash = int; + struct BadAlloc {}; + // The only requirement in the Standard is that integral types cannot be + // considered input iterators, beyond that it is unspecified. + using BadIter = int; +#ifdef _LIBCPP_VERSION + using OutputIter = std::insert_iterator; +#endif // _LIBCPP_VERSION + using AllocAsHash = Alloc; + using AllocAsPred = Alloc; + + // (iter, iter) + // + // Cannot deduce from (BAD_iter, BAD_iter) + static_assert(SFINAEs_away); + LIBCPP_STATIC_ASSERT(SFINAEs_away); + + // (iter, iter, buckets) + // + // Cannot deduce from (BAD_iter, BAD_iter, buckets) + static_assert(SFINAEs_away); + LIBCPP_STATIC_ASSERT(SFINAEs_away); + + // (iter, iter, buckets, hash) + // + // Cannot deduce from (BAD_iter, BAD_iter, buckets, hash) + static_assert(SFINAEs_away); + LIBCPP_STATIC_ASSERT( + SFINAEs_away); + // Cannot deduce from (iter, iter, buckets, BAD_hash) + static_assert(SFINAEs_away); + // Note: (iter, iter, buckets, ALLOC_as_hash) is allowed -- it just calls + // (iter, iter, buckets, alloc) + + // (iter, iter, buckets, hash, pred) + // + // Cannot deduce from (BAD_iter, BAD_iter, buckets, hash, pred) + static_assert(SFINAEs_away); + LIBCPP_STATIC_ASSERT( + SFINAEs_away); + // Cannot deduce from (iter, iter, buckets, BAD_hash, pred) + static_assert(SFINAEs_away); + // Cannot deduce from (iter, iter, buckets, ALLOC_as_hash, pred) + static_assert(SFINAEs_away); + // Note: (iter, iter, buckets, hash, ALLOC_as_pred) is allowed -- it just + // calls (iter, iter, buckets, hash, alloc) + + // (iter, iter, buckets, hash, pred, alloc) + // + // Cannot deduce from (BAD_iter, BAD_iter, buckets, hash, pred, alloc) + static_assert( + SFINAEs_away); + LIBCPP_STATIC_ASSERT(SFINAEs_away); + // Cannot deduce from (iter, iter, buckets, BAD_hash, pred, alloc) + static_assert( + SFINAEs_away); + // Cannot deduce from (iter, iter, buckets, ALLOC_as_hash, pred, alloc) + static_assert( + SFINAEs_away); + // Cannot deduce from (iter, iter, buckets, hash, ALLOC_as_pred, alloc) + static_assert( + SFINAEs_away); + // Cannot deduce from (iter, iter, buckets, hash, pred, BAD_alloc) + static_assert( + SFINAEs_away); + + // (iter, iter, buckets, alloc) + // + // Cannot deduce from (BAD_iter, BAD_iter, buckets, alloc) + static_assert(SFINAEs_away); + LIBCPP_STATIC_ASSERT( + SFINAEs_away); + // Note: (iter, iter, buckets, BAD_alloc) is interpreted as (iter, iter, + // buckets, hash), which is valid because the only requirement for the hash + // parameter is that it's not integral. + + // (iter, iter, alloc) + // + // Cannot deduce from (BAD_iter, BAD_iter, alloc) + static_assert(SFINAEs_away); + LIBCPP_STATIC_ASSERT(SFINAEs_away); + // Cannot deduce from (iter, iter, BAD_alloc) + static_assert(SFINAEs_away); + + // (iter, iter, buckets, hash, alloc) + // + // Cannot deduce from (BAD_iter, BAD_iter, buckets, hash, alloc) + static_assert(SFINAEs_away); + LIBCPP_STATIC_ASSERT( + SFINAEs_away); + // Cannot deduce from (iter, iter, buckets, BAD_hash, alloc) + static_assert(SFINAEs_away); + // Cannot deduce from (iter, iter, buckets, ALLOC_as_hash, alloc) + static_assert( + SFINAEs_away); + // Note: (iter, iter, buckets, hash, BAD_alloc) is interpreted as (iter, iter, + // buckets, hash, pred), which is valid because there are no requirements for + // the predicate. + + // (init_list, buckets, hash) + // + // Cannot deduce from (init_list, buckets, BAD_hash) + static_assert(SFINAEs_away); + // Note: (init_list, buckets, ALLOC_as_hash) is interpreted as (init_list, + // buckets, alloc), which is valid. + + // (init_list, buckets, hash, pred) + // + // Cannot deduce from (init_list, buckets, BAD_hash, pred) + static_assert(SFINAEs_away); + // Cannot deduce from (init_list, buckets, ALLOC_as_hash, pred) + static_assert(SFINAEs_away); + // Note: (init_list, buckets, hash, ALLOC_as_pred) is interpreted as + // (init_list, buckets, hash, alloc), which is valid. + + // (init_list, buckets, hash, pred, alloc) + // + // Cannot deduce from (init_list, buckets, BAD_hash, pred, alloc) + static_assert( + SFINAEs_away); + // Cannot deduce from (init_list, buckets, ALLOC_as_hash, pred, alloc) + static_assert( + SFINAEs_away); + // Cannot deduce from (init_list, buckets, hash, ALLOC_as_pred, alloc) + static_assert( + SFINAEs_away); + // Cannot deduce from (init_list, buckets, hash, pred, BAD_alloc) + static_assert( + SFINAEs_away); + + // (init_list, buckets, alloc) + // + // Note: (init_list, buckets, BAD_alloc) is interpreted as (init_list, + // buckets, hash), which is valid because the only requirement for the hash + // parameter is that it's not integral. + + // (init_list, buckets, hash, alloc) + // + // Cannot deduce from (init_list, buckets, BAD_hash, alloc) + static_assert(SFINAEs_away); + // Cannot deduce from (init_list, buckets, ALLOC_as_hash, alloc) + static_assert(SFINAEs_away); + + // (init_list, alloc) + // + // Cannot deduce from (init_list, BAD_alloc) + static_assert(SFINAEs_away); +} + +#endif // TEST_SUPPORT_DEDUCTION_GUIDES_SFINAE_CHECKS_H