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 ``<regex>`` 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 <https://wg21.link/P0298R3>`__","CWG","A byte type definition","Kona","|Complete|","5.0" "`P0317R1 <https://wg21.link/P0317R1>`__","LWG","Directory Entry Caching for Filesystem","Kona","|Complete|","7.0" "`P0430R2 <https://wg21.link/P0430R2>`__","LWG","File system library on non-POSIX-like operating systems","Kona","|Complete|","7.0" -"`P0433R2 <https://wg21.link/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 <https://wg21.link/P0433R2>`__","LWG","Toward a resolution of US7 and US14: Integrating template deduction for class templates into the standard library","Kona","|Complete|","14.0" "`P0452R1 <https://wg21.link/P0452R1>`__","LWG","Unifying <numeric> Parallel Algorithms","Kona","","" "`P0467R2 <https://wg21.link/P0467R2>`__","LWG","Iterator Concerns for Parallel Algorithms","Kona","","" "`P0492R2 <https://wg21.link/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 <class _Alloc, class _ValueType = typename _Alloc::value_type> +struct _LIBCPP_TEMPLATE_VIS __allocator_traits : allocator_traits<_Alloc> {}; + template <class _Traits, class _Tp> 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 <class InputIterator, class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>> deque(InputIterator, InputIterator, Allocator = Allocator()) - -> deque<typename iterator_traits<InputIterator>::value_type, Allocator>; + -> deque<typename iterator_traits<InputIterator>::value_type, Allocator>; // C++17 template <class T, class Allocator> bool operator==(const deque<T,Allocator>& x, const deque<T,Allocator>& y); @@ -162,6 +162,7 @@ #include <__config> #include <__debug> +#include <__iterator/iterator_traits.h> #include <__split_buffer> #include <__utility/forward.h> #include <algorithm> @@ -1258,20 +1259,20 @@ static_assert((is_same<typename allocator_type::value_type, value_type>::value), "Allocator::value_type must be same type as value_type"); - typedef __deque_base<value_type, allocator_type> __base; + typedef __deque_base<value_type, allocator_type> __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<allocator_type>::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<iterator> reverse_iterator; - typedef _VSTD::reverse_iterator<const_iterator> const_reverse_iterator; + typedef typename __base::pointer pointer; + typedef typename __base::const_pointer const_pointer; + typedef _VSTD::reverse_iterator<iterator> reverse_iterator; + typedef _VSTD::reverse_iterator<const_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 _InputIterator, class _Alloc = allocator<__iter_value_type<_InputIterator>>, + 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<class _InputIterator, class _Alloc, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>, class = enable_if_t<__is_allocator<_Alloc>::value> > deque(_InputIterator, _InputIterator, _Alloc) -> deque<__iter_value_type<_InputIterator>, _Alloc>; #endif - template <class _Tp, class _Allocator> 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<allocator_type>::pointer pointer; typedef typename allocator_traits<allocator_type>::const_pointer const_pointer; - typedef typename allocator_traits<allocator_type>::size_type size_type; + typedef typename __allocator_traits<allocator_type>::size_type size_type; typedef typename allocator_traits<allocator_type>::difference_type difference_type; typedef typename base::iterator iterator; @@ -873,6 +873,7 @@ #if _LIBCPP_STD_VER >= 17 template<class _InputIterator, class _Alloc = allocator<__iter_value_type<_InputIterator>>, + 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<class _InputIterator, class _Alloc, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::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_type, typename allocator_type::value_type>::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<iterator> reverse_iterator; - typedef _VSTD::reverse_iterator<const_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<allocator_type>::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<iterator> reverse_iterator; + typedef _VSTD::reverse_iterator<const_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 _InputIterator, class _Alloc = allocator<__iter_value_type<_InputIterator>>, + 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<class _InputIterator, class _Alloc, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::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<const_iterator,const_iterator> equal_range(const K& x) const; // C++14 }; +template <class InputIterator, + class Compare = less<iter_key_t<InputIterator>>, + class Allocator = allocator<iter_to_alloc_t<InputIterator>>> +map(InputIterator, InputIterator, Compare = Compare(), Allocator = Allocator()) + -> map<iter_key_t<InputIterator>, iter_val_t<InputIterator>, Compare, Allocator>; // C++17 + +template<class Key, class T, class Compare = less<Key>, + class Allocator = allocator<pair<const Key, T>>> +map(initializer_list<pair<const Key, T>>, Compare = Compare(), Allocator = Allocator()) + -> map<Key, T, Compare, Allocator>; // C++17 + +template <class InputIterator, class Allocator> +map(InputIterator, InputIterator, Allocator) + -> map<iter_key_t<InputIterator>, iter_val_t<InputIterator>, less<iter_key_t<InputIterator>>, + Allocator>; // C++17 + +template<class Key, class T, class Allocator> +map(initializer_list<pair<const Key, T>>, Allocator) -> map<Key, T, less<Key>, Allocator>; // C++17 + template <class Key, class T, class Compare, class Allocator> bool operator==(const map<Key, T, Compare, Allocator>& x, @@ -444,6 +463,26 @@ pair<const_iterator,const_iterator> equal_range(const K& x) const; // C++14 }; +template <class InputIterator, + class Compare = less<iter_key_t<InputIterator>>, + class Allocator = allocator<iter_to_alloc_t<InputIterator>>> +multimap(InputIterator, InputIterator, Compare = Compare(), Allocator = Allocator()) + -> multimap<iter_key_t<InputIterator>, iter_val_t<InputIterator>, Compare, Allocator>; // C++17 + +template<class Key, class T, class Compare = less<Key>, + class Allocator = allocator<pair<const Key, T>>> +multimap(initializer_list<pair<const Key, T>>, Compare = Compare(), Allocator = Allocator()) + -> multimap<Key, T, Compare, Allocator>; // C++17 + +template <class InputIterator, class Allocator> +multimap(InputIterator, InputIterator, Allocator) + -> multimap<iter_key_t<InputIterator>, iter_val_t<InputIterator>, + less<iter_key_t<InputIterator>>, Allocator>; // C++17 + +template<class Key, class T, class Allocator> +multimap(initializer_list<pair<const Key, T>>, Allocator) + -> multimap<Key, T, less<Key>, Allocator>; // C++17 + template <class Key, class T, class Compare, class Allocator> bool operator==(const multimap<Key, T, Compare, Allocator>& 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 _InputIterator, class _Compare = less<__iter_key_type<_InputIterator>>, class _Allocator = allocator<__iter_to_alloc_type<_InputIterator>>, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value, void>, class = enable_if_t<!__is_allocator<_Compare>::value, void>, class = enable_if_t<__is_allocator<_Allocator>::value, void>> map(_InputIterator, _InputIterator, _Compare = _Compare(), _Allocator = _Allocator()) @@ -1514,6 +1555,7 @@ -> map<remove_const_t<_Key>, _Tp, _Compare, _Allocator>; template<class _InputIterator, class _Allocator, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::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 _InputIterator, class _Compare = less<__iter_key_type<_InputIterator>>, class _Allocator = allocator<__iter_to_alloc_type<_InputIterator>>, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value, void>, class = enable_if_t<!__is_allocator<_Compare>::value, void>, class = enable_if_t<__is_allocator<_Allocator>::value, void>> multimap(_InputIterator, _InputIterator, _Compare = _Compare(), _Allocator = _Allocator()) @@ -2187,6 +2230,7 @@ -> multimap<remove_const_t<_Key>, _Tp, _Compare, _Allocator>; template<class _InputIterator, class _Allocator, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::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<iter-value-type<InputIterator>, vector<iter-value-type<InputIterator>, Allocator>, - less<iter-value-type<InputIterator>>>; + less<iter-value-type<InputIterator>>>; // C++17 template<class InputIterator, class Compare, class Allocator> priority_queue(InputIterator, InputIterator, Compare, Allocator) -> priority_queue<iter-value-type<InputIterator>, - vector<iter-value-type<InputIterator>, Allocator>, Compare>; + vector<iter-value-type<InputIterator>, Allocator>, Compare>; // C++17 template<class InputIterator, class Compare, class Container, class Allocator> priority_queue(InputIterator, InputIterator, Compare, Container, Allocator) - -> priority_queue<typename Container::value_type, Container, Compare>; + -> priority_queue<typename Container::value_type, Container, Compare>; // C++17 template <class T, class Container, class Compare> void swap(priority_queue<T, Container, Compare>& x, diff --git a/libcxx/include/set b/libcxx/include/set --- a/libcxx/include/set +++ b/libcxx/include/set @@ -183,6 +183,25 @@ pair<const_iterator,const_iterator> equal_range(const K& x) const; // C++14 }; +template <class InputIterator, + class Compare = less<typename iterator_traits<InputIterator>::value_type>, + class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>> +set(InputIterator, InputIterator, + Compare = Compare(), Allocator = Allocator()) + -> set<typename iterator_traits<InputIterator>::value_type, Compare, Allocator>; // C++17 + +template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>> +set(initializer_list<Key>, Compare = Compare(), Allocator = Allocator()) + -> set<Key, Compare, Allocator>; // C++17 + +template<class InputIterator, class Allocator> +set(InputIterator, InputIterator, Allocator) + -> set<typename iterator_traits<InputIterator>::value_type, + less<typename iterator_traits<InputIterator>::value_type>, Allocator>; // C++17 + +template<class Key, class Allocator> +set(initializer_list<Key>, Allocator) -> set<Key, less<Key>, Allocator>; // C++17 + template <class Key, class Compare, class Allocator> bool operator==(const set<Key, Compare, Allocator>& x, @@ -389,6 +408,25 @@ pair<const_iterator,const_iterator> equal_range(const K& x) const; // C++14 }; +template <class InputIterator, + class Compare = less<typename iterator_traits<InputIterator>::value_type>, + class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>> +multiset(InputIterator, InputIterator, + Compare = Compare(), Allocator = Allocator()) + -> multiset<typename iterator_traits<InputIterator>::value_type, Compare, Allocator>; // C++17 + +template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>> +multiset(initializer_list<Key>, Compare = Compare(), Allocator = Allocator()) + -> multiset<Key, Compare, Allocator>; // C++17 + +template<class InputIterator, class Allocator> +multiset(InputIterator, InputIterator, Allocator) + -> multiset<typename iterator_traits<InputIterator>::value_type, + less<typename iterator_traits<InputIterator>::value_type>, Allocator>; // C++17 + +template<class Key, class Allocator> +multiset(initializer_list<Key>, Allocator) -> multiset<Key, less<Key>, Allocator>; // C++17 + template <class Key, class Compare, class Allocator> bool operator==(const multiset<Key, Compare, Allocator>& 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<value_type, value_compare, allocator_type> __base; typedef allocator_traits<allocator_type> __alloc_traits; - typedef typename __base::__node_holder __node_holder; __base __tree_; @@ -872,6 +910,7 @@ template<class _InputIterator, class _Compare = less<__iter_value_type<_InputIterator>>, 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<!__is_allocator<_Compare>::value, void>> set(_InputIterator, _InputIterator, _Compare = _Compare(), _Allocator = _Allocator()) @@ -879,12 +918,13 @@ template<class _Key, class _Compare = less<_Key>, class _Allocator = allocator<_Key>, - class = enable_if_t<__is_allocator<_Allocator>::value, void>, - class = enable_if_t<!__is_allocator<_Compare>::value, void>> + class = enable_if_t<!__is_allocator<_Compare>::value, void>, + class = enable_if_t<__is_allocator<_Allocator>::value, void>> set(initializer_list<_Key>, _Compare = _Compare(), _Allocator = _Allocator()) -> set<_Key, _Compare, _Allocator>; template<class _InputIterator, class _Allocator, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::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<value_type, value_compare, allocator_type> __base; typedef allocator_traits<allocator_type> __alloc_traits; - typedef typename __base::__node_holder __node_holder; __base __tree_; @@ -1403,6 +1442,7 @@ template<class _InputIterator, class _Compare = less<__iter_value_type<_InputIterator>>, 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<!__is_allocator<_Compare>::value, void>> multiset(_InputIterator, _InputIterator, _Compare = _Compare(), _Allocator = _Allocator()) @@ -1416,6 +1456,7 @@ -> multiset<_Key, _Compare, _Allocator>; template<class _InputIterator, class _Allocator, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::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 InputIterator, + class Hash = hash<iter_key_t<InputIterator>>, class Pred = equal_to<iter_key_t<InputIterator>>, + class Allocator = allocator<iter_to_alloc_t<InputIterator>>> +unordered_map(InputIterator, InputIterator, typename see below::size_type = see below, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_map<iter_key_t<InputIterator>, iter_value_t<InputIterator>, Hash, Pred, + Allocator>; // C++17 + +template<class Key, class T, class Hash = hash<Key>, + class Pred = equal_to<Key>, class Allocator = allocator<pair<const Key, T>>> +unordered_map(initializer_list<pair<const Key, T>>, typename see below::size_type = see below, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_map<Key, T, Hash, Pred, Allocator>; // C++17 + +template<class InputIterator, class Allocator> +unordered_map(InputIterator, InputIterator, typename see below::size_type, Allocator) + -> unordered_map<iter_key_t<InputIterator>, iter_val_t<InputIterator>, + hash<iter_key_t<InputIterator>>, equal_to<iter_key_t<InputIterator>>, Allocator>; // C++17 + +template<class InputIterator, class Allocator> +unordered_map(InputIterator, InputIterator, Allocator) + -> unordered_map<iter_key_t<InputIterator>, iter_val_t<InputIterator>, + hash<iter_key_t<InputIterator>>, equal_to<iter_key_t<InputIterator>>, Allocator>; // C++17 + +template<class InputIterator, class Hash, class Allocator> +unordered_map(InputIterator, InputIterator, typename see below::size_type, Hash, Allocator) + -> unordered_map<iter_key_t<InputIterator>, iter_val_t<InputIterator>, Hash, + equal_to<iter_key_t<InputIterator>>, Allocator>; // C++17 + +template<class Key, class T, typename Allocator> +unordered_map(initializer_list<pair<const Key, T>>, typename see below::size_type, Allocator) + -> unordered_map<Key, T, hash<Key>, equal_to<Key>, Allocator>; // C++17 + +template<class Key, class T, typename Allocator> +unordered_map(initializer_list<pair<const Key, T>>, Allocator) + -> unordered_map<Key, T, hash<Key>, equal_to<Key>, Allocator>; // C++17 + +template<class Key, class T, class Hash, class Allocator> +unordered_map(initializer_list<pair<const Key, T>>, typename see below::size_type, Hash, Allocator) + -> unordered_map<Key, T, Hash, equal_to<Key>, Allocator>; // C++17 + template <class Key, class T, class Hash, class Pred, class Alloc> void swap(unordered_map<Key, T, Hash, Pred, Alloc>& x, unordered_map<Key, T, Hash, Pred, Alloc>& y) @@ -404,6 +445,48 @@ void reserve(size_type n); }; +template<class InputIterator, + class Hash = hash<iter_key_t<InputIterator>>, class Pred = equal_to<iter_key_t<InputIterator>>, + class Allocator = allocator<iter_to_alloc_t<InputIterator>>> +unordered_multimap(InputIterator, InputIterator, typename see below::size_type = see below, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_multimap<iter_key_t<InputIterator>, iter_value_t<InputIterator>, Hash, Pred, + Allocator>; // C++17 + +template<class Key, class T, class Hash = hash<Key>, + class Pred = equal_to<Key>, class Allocator = allocator<pair<const Key, T>>> +unordered_multimap(initializer_list<pair<const Key, T>>, typename see below::size_type = see below, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_multimap<Key, T, Hash, Pred, Allocator>; // C++17 + +template<class InputIterator, class Allocator> +unordered_multimap(InputIterator, InputIterator, typename see below::size_type, Allocator) + -> unordered_multimap<iter_key_t<InputIterator>, iter_val_t<InputIterator>, + hash<iter_key_t<InputIterator>>, equal_to<iter_key_t<InputIterator>>, Allocator>; // C++17 + +template<class InputIterator, class Allocator> +unordered_multimap(InputIterator, InputIterator, Allocator) + -> unordered_multimap<iter_key_t<InputIterator>, iter_val_t<InputIterator>, + hash<iter_key_t<InputIterator>>, equal_to<iter_key_t<InputIterator>>, Allocator>; // C++17 + +template<class InputIterator, class Hash, class Allocator> +unordered_multimap(InputIterator, InputIterator, typename see below::size_type, Hash, Allocator) + -> unordered_multimap<iter_key_t<InputIterator>, iter_val_t<InputIterator>, Hash, + equal_to<iter_key_t<InputIterator>>, Allocator>; // C++17 + +template<class Key, class T, typename Allocator> +unordered_multimap(initializer_list<pair<const Key, T>>, typename see below::size_type, Allocator) + -> unordered_multimap<Key, T, hash<Key>, equal_to<Key>, Allocator>; // C++17 + +template<class Key, class T, typename Allocator> +unordered_multimap(initializer_list<pair<const Key, T>>, Allocator) + -> unordered_multimap<Key, T, hash<Key>, equal_to<Key>, Allocator>; // C++17 + +template<class Key, class T, class Hash, class Allocator> +unordered_multimap(initializer_list<pair<const Key, T>>, typename see below::size_type, Hash, + Allocator) + -> unordered_multimap<Key, T, Hash, equal_to<Key>, Allocator>; // C++17 + template <class Key, class T, class Hash, class Pred, class Alloc> void swap(unordered_multimap<Key, T, Hash, Pred, Alloc>& x, unordered_multimap<Key, T, Hash, Pred, Alloc>& 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<!__is_allocator<_Hash>::value>, class = enable_if_t<!is_integral<_Hash>::value>, class = enable_if_t<!__is_allocator<_Pred>::value>, @@ -1490,18 +1575,21 @@ -> unordered_map<remove_const_t<_Key>, _Tp, _Hash, _Pred, _Allocator>; template<class _InputIterator, class _Allocator, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::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<class _InputIterator, class _Allocator, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::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<class _InputIterator, class _Hash, class _Allocator, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>, class = enable_if_t<!__is_allocator<_Hash>::value>, class = enable_if_t<!is_integral<_Hash>::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<!__is_allocator<_Hash>::value>, class = enable_if_t<!is_integral<_Hash>::value>, class = enable_if_t<!__is_allocator<_Pred>::value>, @@ -2288,18 +2377,21 @@ -> unordered_multimap<remove_const_t<_Key>, _Tp, _Hash, _Pred, _Allocator>; template<class _InputIterator, class _Allocator, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::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<class _InputIterator, class _Allocator, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::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<class _InputIterator, class _Hash, class _Allocator, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>, class = enable_if_t<!__is_allocator<_Hash>::value>, class = enable_if_t<!is_integral<_Hash>::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<class InputIterator, + class Hash = hash<typename iterator_traits<InputIterator>::value_type>, + class Pred = equal_to<typename iterator_traits<InputIterator>::value_type>, + class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>> +unordered_set(InputIterator, InputIterator, typename see below::size_type = see below, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_set<typename iterator_traits<InputIterator>::value_type, + Hash, Pred, Allocator>; // C++17 + +template<class T, class Hash = hash<T>, + class Pred = equal_to<T>, class Allocator = allocator<T>> +unordered_set(initializer_list<T>, typename see below::size_type = see below, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_set<T, Hash, Pred, Allocator>; // C++17 + +template<class InputIterator, class Allocator> +unordered_set(InputIterator, InputIterator, typename see below::size_type, Allocator) + -> unordered_set<typename iterator_traits<InputIterator>::value_type, + hash<typename iterator_traits<InputIterator>::value_type>, + equal_to<typename iterator_traits<InputIterator>::value_type>, + Allocator>; // C++17 + +template<class InputIterator, class Hash, class Allocator> +unordered_set(InputIterator, InputIterator, typename see below::size_type, + Hash, Allocator) + -> unordered_set<typename iterator_traits<InputIterator>::value_type, Hash, + equal_to<typename iterator_traits<InputIterator>::value_type>, + Allocator>; // C++17 + +template<class T, class Allocator> +unordered_set(initializer_list<T>, typename see below::size_type, Allocator) + -> unordered_set<T, hash<T>, equal_to<T>, Allocator>; // C++17 + +template<class T, class Hash, class Allocator> +unordered_set(initializer_list<T>, typename see below::size_type, Hash, Allocator) + -> unordered_set<T, Hash, equal_to<T>, Allocator>; // C++17 + template <class Value, class Hash, class Pred, class Alloc> void swap(unordered_set<Value, Hash, Pred, Alloc>& x, unordered_set<Value, Hash, Pred, Alloc>& y) @@ -359,6 +396,42 @@ void reserve(size_type n); }; +template<class InputIterator, + class Hash = hash<typename iterator_traits<InputIterator>::value_type>, + class Pred = equal_to<typename iterator_traits<InputIterator>::value_type>, + class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>> +unordered_multiset(InputIterator, InputIterator, see below::size_type = see below, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_multiset<typename iterator_traits<InputIterator>::value_type, + Hash, Pred, Allocator>; // C++17 + +template<class T, class Hash = hash<T>, + class Pred = equal_to<T>, class Allocator = allocator<T>> +unordered_multiset(initializer_list<T>, typename see below::size_type = see below, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_multiset<T, Hash, Pred, Allocator>; // C++17 + +template<class InputIterator, class Allocator> +unordered_multiset(InputIterator, InputIterator, typename see below::size_type, Allocator) + -> unordered_multiset<typename iterator_traits<InputIterator>::value_type, + hash<typename iterator_traits<InputIterator>::value_type>, + equal_to<typename iterator_traits<InputIterator>::value_type>, + Allocator>; // C++17 + +template<class InputIterator, class Hash, class Allocator> +unordered_multiset(InputIterator, InputIterator, typename see below::size_type, + Hash, Allocator) + -> unordered_multiset<typename iterator_traits<InputIterator>::value_type, Hash, + equal_to<typename iterator_traits<InputIterator>::value_type>, Allocator>; // C++17 + +template<class T, class Allocator> +unordered_multiset(initializer_list<T>, typename see below::size_type, Allocator) + -> unordered_multiset<T, hash<T>, equal_to<T>, Allocator>; // C++17 + +template<class T, class Hash, class Allocator> +unordered_multiset(initializer_list<T>, typename see below::size_type, Hash, Allocator) + -> unordered_multiset<T, Hash, equal_to<T>, Allocator>; // C++17 + template <class Value, class Hash, class Pred, class Alloc> void swap(unordered_multiset<Value, Hash, Pred, Alloc>& x, unordered_multiset<Value, Hash, Pred, Alloc>& 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<!__is_allocator<_Hash>::value>, class = enable_if_t<!is_integral<_Hash>::value>, class = enable_if_t<!__is_allocator<_Pred>::value>, @@ -823,6 +897,7 @@ -> unordered_set<_Tp, _Hash, _Pred, _Allocator>; template<class _InputIterator, class _Allocator, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::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<class _InputIterator, class _Hash, class _Allocator, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>, class = enable_if_t<!__is_allocator<_Hash>::value>, class = enable_if_t<!is_integral<_Hash>::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<!__is_allocator<_Hash>::value>, class = enable_if_t<!is_integral<_Hash>::value>, class = enable_if_t<!__is_allocator<_Pred>::value>, @@ -1487,6 +1564,7 @@ -> unordered_multiset<_Tp, _Hash, _Pred, _Allocator>; template<class _InputIterator, class _Allocator, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::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<class _InputIterator, class _Hash, class _Allocator, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>, class = enable_if_t<!__is_allocator<_Hash>::value>, class = enable_if_t<!is_integral<_Hash>::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 <class InputIterator, class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>> vector(InputIterator, InputIterator, Allocator = Allocator()) - -> vector<typename iterator_traits<InputIterator>::value_type, Allocator>; + -> vector<typename iterator_traits<InputIterator>::value_type, Allocator>; // C++17 template <class Allocator> struct hash<std::vector<bool, Allocator>>; @@ -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 _InputIterator, class _Alloc = allocator<__iter_value_type<_InputIterator>>, + 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<class _InputIterator, class _Alloc, + class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::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 <map> #include <type_traits> +#include "deduction_guides_sfinae_checks.h" #include "test_allocator.h" using P = std::pair<int, long>; @@ -151,5 +152,7 @@ ASSERT_SAME_TYPE(decltype(m2), std::map<int, int>); } + AssociativeContainerDeductionGuidesSfinaeAway<std::map, std::map<int, long>>(); + 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 <map> #include <type_traits> +#include "deduction_guides_sfinae_checks.h" #include "test_allocator.h" using P = std::pair<int, long>; @@ -151,5 +152,7 @@ ASSERT_SAME_TYPE(decltype(m2), std::multimap<int, int>); } + AssociativeContainerDeductionGuidesSfinaeAway<std::multimap, std::multimap<int, long>>(); + 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 <set> #include <type_traits> +#include "deduction_guides_sfinae_checks.h" #include "test_allocator.h" struct NotAnAllocator { @@ -186,5 +187,7 @@ assert(s.size() == 2); } + AssociativeContainerDeductionGuidesSfinaeAway<std::multiset, std::multiset<int>>(); + 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 <set> #include <type_traits> +#include "deduction_guides_sfinae_checks.h" #include "test_allocator.h" struct NotAnAllocator { @@ -184,5 +185,7 @@ assert(s.size() == 2); } + AssociativeContainerDeductionGuidesSfinaeAway<std::set, std::set<int>>(); + 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 <cstddef> #include <climits> // 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<int>; + using Cont = std::vector<int>; + using Alloc = std::allocator<int>; + 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<int>; + + // (iter, iter) + // + // Cannot deduce from (BAD_iter, BAD_iter) + static_assert(SFINAEs_away<std::priority_queue, BadIter, BadIter>); + // 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<std::priority_queue, BadIter, BadIter, Comp>); + LIBCPP_STATIC_ASSERT(SFINAEs_away<std::priority_queue, OutputIter, OutputIter, Comp>); + // 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<std::priority_queue, BadIter, BadIter, Comp, Cont>); + LIBCPP_STATIC_ASSERT(SFINAEs_away<std::priority_queue, OutputIter, OutputIter, Comp, Cont>); + // Cannot deduce from (iter, iter, ALLOC_as_comp, cont) + static_assert(SFINAEs_away<std::priority_queue, Iter, Iter, AllocAsComp, Cont>); + // 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<std::priority_queue, BadIter, BadIter, Alloc>); + LIBCPP_STATIC_ASSERT(SFINAEs_away<std::priority_queue, OutputIter, OutputIter, Alloc>); + // 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<std::priority_queue, Iter, Iter, AllocAsComp, Alloc>); + // 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<std::priority_queue, BadIter, BadIter, Comp, Cont, Alloc>); + LIBCPP_STATIC_ASSERT( + SFINAEs_away<std::priority_queue, OutputIter, OutputIter, Comp, Cont, Alloc>); + // Cannot deduce from (iter, iter, ALLOC_as_comp, cont, alloc) + static_assert(SFINAEs_away<std::priority_queue, Iter, Iter, AllocAsComp, Cont, Alloc>); + // Cannot deduce from (iter, iter, comp, ALLOC_as_cont, alloc) + static_assert(SFINAEs_away<std::priority_queue, Iter, Iter, Comp, AllocAsCont, Alloc>); + // Cannot deduce from (iter, iter, comp, cont, BAD_alloc) + static_assert(SFINAEs_away<std::priority_queue, Iter, Iter, Comp, Cont, BadAlloc>); + // Cannot deduce from (iter, iter, comp, cont, DIFFERENT_alloc) + static_assert(SFINAEs_away<std::priority_queue, Iter, Iter, Comp, Cont, DiffAlloc>); + + // (comp, alloc) + // + // Cannot deduce from (ALLOC_as_comp, alloc) + static_assert(SFINAEs_away<std::priority_queue, AllocAsComp, Alloc>); + // Cannot deduce from (comp, BAD_alloc) + static_assert(SFINAEs_away<std::priority_queue, Comp, BadAlloc>); + + // (comp, cont, alloc) + // + // Cannot deduce from (ALLOC_as_comp, cont, alloc) + static_assert(SFINAEs_away<std::priority_queue, AllocAsComp, Cont, Alloc>); + // Cannot deduce from (comp, ALLOC_as_cont, alloc) + static_assert(SFINAEs_away<std::priority_queue, Comp, AllocAsCont, Alloc>); + // Cannot deduce from (comp, cont, BAD_alloc) + static_assert(SFINAEs_away<std::priority_queue, Comp, Cont, BadAlloc>); + // Cannot deduce from (comp, cont, DIFFERENT_alloc) + static_assert(SFINAEs_away<std::priority_queue, Comp, Cont, DiffAlloc>); + + // (comp, cont) + // + // Cannot deduce from (ALLOC_as_comp, cont) + static_assert(SFINAEs_away<std::priority_queue, AllocAsComp, Cont>); + // Cannot deduce from (comp, ALLOC_as_cont) + static_assert(SFINAEs_away<std::priority_queue, Comp, AllocAsCont>); + } + 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 <iterator> #include <cassert> #include <cstddef> -#include <climits> // 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<int>; + using Alloc = std::allocator<int>; + using DiffAlloc = test_allocator<int>; + + struct BadAlloc {}; + using AllocAsCont = Alloc; + + // (cont, alloc) + // + // Cannot deduce from (ALLOC_as_cont, alloc) + static_assert(SFINAEs_away<std::queue, AllocAsCont, BadAlloc>); + // Cannot deduce from (cont, BAD_alloc) + static_assert(SFINAEs_away<std::queue, Cont, BadAlloc>); + // Cannot deduce from (cont, DIFFERENT_alloc) + static_assert(SFINAEs_away<std::queue, Cont, DiffAlloc>); + } + 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 <cstddef> #include <climits> // 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<int>; + using Alloc = std::allocator<int>; + using DiffAlloc = test_allocator<int>; + + struct BadAlloc {}; + using AllocAsCont = Alloc; + + // (cont, alloc) + // + // Cannot deduce from (ALLOC_as_cont, alloc) + static_assert(SFINAEs_away<std::stack, AllocAsCont, Alloc>); + // Cannot deduce from (cont, BAD_alloc) + static_assert(SFINAEs_away<std::stack, Cont, BadAlloc>); + // Cannot deduce from (cont, DIFFERENT_alloc) + static_assert(SFINAEs_away<std::stack, Cont, DiffAlloc>); + } + 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 <cstddef> #include <climits> // 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<std::deque, std::deque<int>>(); + 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 <cstddef> #include <climits> // 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<std::forward_list, std::forward_list<int>>(); + 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 <cstddef> #include <climits> // 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<std::list, std::list<int>>(); + 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 <vector> -#include <iterator> #include <cassert> #include <cstddef> #include <climits> // INT_MAX +#include <iterator> +#include <type_traits> +#include "deduction_guides_sfinae_checks.h" #include "test_macros.h" #include "test_iterators.h" #include "test_allocator.h" @@ -139,5 +141,7 @@ } } + SequenceContainerDeductionGuidesSfinaeAway<std::vector, std::vector<int>>(); + 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 <type_traits> #include <unordered_map> +#include "deduction_guides_sfinae_checks.h" #include "test_allocator.h" using P = std::pair<int, long>; @@ -218,5 +219,7 @@ ASSERT_SAME_TYPE(decltype(m2), std::unordered_map<int, int>); } + UnorderedContainerDeductionGuidesSfinaeAway<std::unordered_map, std::unordered_map<int, long>>(); + 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 <type_traits> #include <unordered_map> +#include "deduction_guides_sfinae_checks.h" #include "test_allocator.h" using P = std::pair<int, long>; @@ -218,5 +219,7 @@ ASSERT_SAME_TYPE(decltype(m2), std::unordered_multimap<int, int>); } + UnorderedContainerDeductionGuidesSfinaeAway<std::unordered_multimap, std::unordered_multimap<int, long>>(); + 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 <type_traits> #include <unordered_set> +#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<std::unordered_multiset, std::unordered_multiset<int>>(); + 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 <type_traits> #include <unordered_set> +#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<std::unordered_set, std::unordered_set<int>>(); + 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 + +// <memory> + +// 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>&& d) noexcept + +#include <memory> + +#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<std::unique_ptr, int*>); + // Cannot deduce from (array). + static_assert(SFINAEs_away<std::unique_ptr, int[]>); + // Cannot deduce from (ptr, Deleter&&). + static_assert(SFINAEs_away<std::unique_ptr, int*, Deleter&&>); + // Cannot deduce from (array, Deleter&&). + static_assert(SFINAEs_away<std::unique_ptr, int[], Deleter&&>); + // Cannot deduce from (ptr, const Deleter&). + static_assert(SFINAEs_away<std::unique_ptr, int*, const Deleter&>); + // Cannot deduce from (array, const Deleter&). + static_assert(SFINAEs_away<std::unique_ptr, int[], const Deleter&>); + + 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 <initializer_list> +#include <memory> +#include <type_traits> +#include <utility> + +#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<template<typename ...> class Instantiated, class ...CtrArgs, + class = decltype(Instantiated(std::declval<CtrArgs>()...))> +std::false_type SFINAEs_away_impl(int); + +template<template<typename ...> class Instantiated, class ...CtrArgs> +std::true_type SFINAEs_away_impl(...); + +template<template<typename ...> class Instantiated, class ...CtrArgs> +constexpr bool SFINAEs_away = + decltype(SFINAEs_away_impl<Instantiated, CtrArgs...>(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<template<typename ...> class Container, typename InstantiatedContainer> +constexpr void SequenceContainerDeductionGuidesSfinaeAway() { + using Alloc = std::allocator<int>; + 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<InstantiatedContainer>; +#endif // _LIBCPP_VERSION + + // (iter, iter) + // + // Cannot deduce from (BAD_iter, BAD_iter) + LIBCPP_STATIC_ASSERT(SFINAEs_away<Container, OutputIter, OutputIter>); + + // (iter, iter, alloc) + // + // Cannot deduce from (BAD_iter, BAD_iter, alloc) + LIBCPP_STATIC_ASSERT(SFINAEs_away<Container, OutputIter, OutputIter, Alloc>); + // Cannot deduce from (iter, iter, BAD_alloc) + static_assert(SFINAEs_away<Container, Iter, Iter, BadAlloc>); + + // (alloc) + // + // Cannot deduce from (alloc) + static_assert(SFINAEs_away<Container, Alloc>); +} + +// 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<template<typename ...> class Container, typename InstantiatedContainer> +constexpr void AssociativeContainerDeductionGuidesSfinaeAway() { + using ValueType = typename InstantiatedContainer::value_type; + using Comp = std::less<int>; + using Alloc = std::allocator<ValueType>; + using Iter = ValueType*; + using InitList = std::initializer_list<ValueType>; + + 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<InstantiatedContainer>; +#endif // _LIBCPP_VERSION + using AllocAsComp = Alloc; + + // (iter, iter) + // + // Cannot deduce from (BAD_iter, BAD_iter) + static_assert(SFINAEs_away<Container, BadIter, BadIter>); + LIBCPP_STATIC_ASSERT(SFINAEs_away<Container, OutputIter, OutputIter>); + + // (iter, iter, comp) + // + // Cannot deduce from (BAD_iter, BAD_iter, comp) + static_assert(SFINAEs_away<Container, BadIter, BadIter, Comp>); + LIBCPP_STATIC_ASSERT(SFINAEs_away<Container, OutputIter, OutputIter, Comp>); + + // (iter, iter, comp, alloc) + // + // Cannot deduce from (BAD_iter, BAD_iter, comp, alloc) + static_assert(SFINAEs_away<Container, BadIter, BadIter, Comp, Alloc>); + LIBCPP_STATIC_ASSERT( + SFINAEs_away<Container, OutputIter, OutputIter, Comp, Alloc>); + // Cannot deduce from (iter, iter, ALLOC_as_comp, alloc) + static_assert(SFINAEs_away<Container, Iter, Iter, AllocAsComp, Alloc>); + // Cannot deduce from (iter, iter, comp, BAD_alloc) + static_assert(SFINAEs_away<Container, Iter, Iter, Comp, BadAlloc>); + + // (iter, iter, alloc) + // + // Cannot deduce from (BAD_iter, BAD_iter, alloc) + static_assert(SFINAEs_away<Container, BadIter, BadIter, Alloc>); + LIBCPP_STATIC_ASSERT(SFINAEs_away<Container, OutputIter, OutputIter, Alloc>); + // 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<Container, InitList, AllocAsComp, Alloc>); + // Cannot deduce from (init_list, comp, BAD_alloc) + static_assert(SFINAEs_away<Container, InitList, Comp, BadAlloc>); + + // (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<template<typename ...> class Container, typename InstantiatedContainer> +constexpr void UnorderedContainerDeductionGuidesSfinaeAway() { + using ValueType = typename InstantiatedContainer::value_type; + using Pred = std::equal_to<int>; + using Hash = std::hash<int>; + using Alloc = std::allocator<ValueType>; + using Iter = ValueType*; + using InitList = std::initializer_list<ValueType>; + + 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<InstantiatedContainer>; +#endif // _LIBCPP_VERSION + using AllocAsHash = Alloc; + using AllocAsPred = Alloc; + + // (iter, iter) + // + // Cannot deduce from (BAD_iter, BAD_iter) + static_assert(SFINAEs_away<Container, BadIter, BadIter>); + LIBCPP_STATIC_ASSERT(SFINAEs_away<Container, OutputIter, OutputIter>); + + // (iter, iter, buckets) + // + // Cannot deduce from (BAD_iter, BAD_iter, buckets) + static_assert(SFINAEs_away<Container, BadIter, BadIter, size_t>); + LIBCPP_STATIC_ASSERT(SFINAEs_away<Container, OutputIter, OutputIter, size_t>); + + // (iter, iter, buckets, hash) + // + // Cannot deduce from (BAD_iter, BAD_iter, buckets, hash) + static_assert(SFINAEs_away<Container, BadIter, BadIter, size_t, Hash>); + LIBCPP_STATIC_ASSERT( + SFINAEs_away<Container, OutputIter, OutputIter, size_t, Hash>); + // Cannot deduce from (iter, iter, buckets, BAD_hash) + static_assert(SFINAEs_away<Container, Iter, Iter, size_t, BadHash>); + // 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<Container, BadIter, BadIter, size_t, Hash, Pred>); + LIBCPP_STATIC_ASSERT( + SFINAEs_away<Container, OutputIter, OutputIter, size_t, Hash, Pred>); + // Cannot deduce from (iter, iter, buckets, BAD_hash, pred) + static_assert(SFINAEs_away<Container, Iter, Iter, size_t, BadHash, Pred>); + // Cannot deduce from (iter, iter, buckets, ALLOC_as_hash, pred) + static_assert(SFINAEs_away<Container, Iter, Iter, size_t, AllocAsHash, Pred>); + // 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<Container, BadIter, BadIter, size_t, Hash, Pred, Alloc>); + LIBCPP_STATIC_ASSERT(SFINAEs_away<Container, OutputIter, OutputIter, + size_t, Hash, Pred, Alloc>); + // Cannot deduce from (iter, iter, buckets, BAD_hash, pred, alloc) + static_assert( + SFINAEs_away<Container, Iter, Iter, size_t, BadHash, Pred, Alloc>); + // Cannot deduce from (iter, iter, buckets, ALLOC_as_hash, pred, alloc) + static_assert( + SFINAEs_away<Container, Iter, Iter, size_t, AllocAsHash, Pred, Alloc>); + // Cannot deduce from (iter, iter, buckets, hash, ALLOC_as_pred, alloc) + static_assert( + SFINAEs_away<Container, Iter, Iter, size_t, Hash, AllocAsPred, Alloc>); + // Cannot deduce from (iter, iter, buckets, hash, pred, BAD_alloc) + static_assert( + SFINAEs_away<Container, Iter, Iter, size_t, Hash, Pred, BadAlloc>); + + // (iter, iter, buckets, alloc) + // + // Cannot deduce from (BAD_iter, BAD_iter, buckets, alloc) + static_assert(SFINAEs_away<Container, BadIter, BadIter, size_t, Alloc>); + LIBCPP_STATIC_ASSERT( + SFINAEs_away<Container, OutputIter, OutputIter, size_t, Alloc>); + // 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<Container, BadIter, BadIter, Alloc>); + LIBCPP_STATIC_ASSERT(SFINAEs_away<Container, OutputIter, OutputIter, Alloc>); + // Cannot deduce from (iter, iter, BAD_alloc) + static_assert(SFINAEs_away<Container, Iter, Iter, BadAlloc>); + + // (iter, iter, buckets, hash, alloc) + // + // Cannot deduce from (BAD_iter, BAD_iter, buckets, hash, alloc) + static_assert(SFINAEs_away<Container, BadIter, BadIter, size_t, Hash, Alloc>); + LIBCPP_STATIC_ASSERT( + SFINAEs_away<Container, OutputIter, OutputIter, size_t, Hash, Alloc>); + // Cannot deduce from (iter, iter, buckets, BAD_hash, alloc) + static_assert(SFINAEs_away<Container, Iter, Iter, size_t, BadHash, Alloc>); + // Cannot deduce from (iter, iter, buckets, ALLOC_as_hash, alloc) + static_assert( + SFINAEs_away<Container, Iter, Iter, size_t, AllocAsHash, Alloc>); + // 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<Container, InitList, size_t, BadHash>); + // 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<Container, InitList, size_t, BadHash, Pred>); + // Cannot deduce from (init_list, buckets, ALLOC_as_hash, pred) + static_assert(SFINAEs_away<Container, InitList, size_t, AllocAsHash, Pred>); + // 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<Container, InitList, size_t, BadHash, Pred, Alloc>); + // Cannot deduce from (init_list, buckets, ALLOC_as_hash, pred, alloc) + static_assert( + SFINAEs_away<Container, InitList, size_t, AllocAsHash, Pred, Alloc>); + // Cannot deduce from (init_list, buckets, hash, ALLOC_as_pred, alloc) + static_assert( + SFINAEs_away<Container, InitList, size_t, Hash, AllocAsPred, Alloc>); + // Cannot deduce from (init_list, buckets, hash, pred, BAD_alloc) + static_assert( + SFINAEs_away<Container, InitList, size_t, Hash, Pred, BadAlloc>); + + // (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<Container, InitList, size_t, BadHash, Alloc>); + // Cannot deduce from (init_list, buckets, ALLOC_as_hash, alloc) + static_assert(SFINAEs_away<Container, InitList, size_t, AllocAsHash, Alloc>); + + // (init_list, alloc) + // + // Cannot deduce from (init_list, BAD_alloc) + static_assert(SFINAEs_away<Container, InitList, BadAlloc>); +} + +#endif // TEST_SUPPORT_DEDUCTION_GUIDES_SFINAE_CHECKS_H