From d6b0352715cfaea5391104aabf2e7079d7df15e8 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Fri, 28 Jun 2024 04:15:26 +0800 Subject: [PATCH] Use `requires`-clauses and concepts for container-like components since C++20 (#4718) Co-authored-by: Stephan T. Lavavej --- stl/inc/deque | 3 +-- stl/inc/forward_list | 3 +-- stl/inc/hash_map | 5 +++++ stl/inc/hash_set | 5 +++++ stl/inc/list | 3 +-- stl/inc/map | 12 ++++++------ stl/inc/queue | 20 +++++++++----------- stl/inc/set | 12 ++++++------ stl/inc/sstream | 10 ++++------ stl/inc/stack | 11 +++++------ stl/inc/unordered_map | 28 ++++++++++++++-------------- stl/inc/unordered_set | 28 ++++++++++++++-------------- stl/inc/vector | 3 +-- stl/inc/xhash | 29 +++++++++++++++++++++-------- stl/inc/xstring | 3 +-- stl/inc/xtree | 17 ++++++++--------- stl/inc/xutility | 23 +++++++++++++++++++++++ 17 files changed, 125 insertions(+), 90 deletions(-) diff --git a/stl/inc/deque b/stl/inc/deque index 905eb1621..2756ad3a2 100644 --- a/stl/inc/deque +++ b/stl/inc/deque @@ -1777,8 +1777,7 @@ deque(_Iter, _Iter, _Alloc = _Alloc()) -> deque<_Iter_value_t<_Iter>, _Alloc>; #endif // _HAS_CXX17 #if _HAS_CXX23 -template <_RANGES input_range _Rng, class _Alloc = allocator<_RANGES range_value_t<_Rng>>, - enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc = allocator<_RANGES range_value_t<_Rng>>> deque(from_range_t, _Rng&&, _Alloc = _Alloc()) -> deque<_RANGES range_value_t<_Rng>, _Alloc>; #endif // _HAS_CXX23 diff --git a/stl/inc/forward_list b/stl/inc/forward_list index 433452691..afcdbf992 100644 --- a/stl/inc/forward_list +++ b/stl/inc/forward_list @@ -1561,8 +1561,7 @@ forward_list(_Iter, _Iter, _Alloc = _Alloc()) -> forward_list<_Iter_value_t<_Ite #endif // _HAS_CXX17 #if _HAS_CXX23 -template <_RANGES input_range _Rng, class _Alloc = allocator<_RANGES range_value_t<_Rng>>, - enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc = allocator<_RANGES range_value_t<_Rng>>> forward_list(from_range_t, _Rng&&, _Alloc = _Alloc()) -> forward_list<_RANGES range_value_t<_Rng>, _Alloc>; #endif // _HAS_CXX23 diff --git a/stl/inc/hash_map b/stl/inc/hash_map index ee9400087..011a06676 100644 --- a/stl/inc/hash_map +++ b/stl/inc/hash_map @@ -58,6 +58,11 @@ namespace stdext { using _Deduce_key = const _Kty&; using key_equal = _Tr; +#if _HAS_CXX20 && defined(__EDG__) // TRANSITION, DevCom-10678753 + template + static constexpr bool _Supports_transparency = false; +#endif // ^^^ workaround ^^^ + _Hmap_traits() = default; _Hmap_traits(const _Tr& _Traits) noexcept(_STD is_nothrow_copy_constructible_v<_Tr>) : _Tr(_Traits) {} diff --git a/stl/inc/hash_set b/stl/inc/hash_set index bd915e7b8..8b7f9a258 100644 --- a/stl/inc/hash_set +++ b/stl/inc/hash_set @@ -53,6 +53,11 @@ namespace stdext { using _Deduce_key = const _Kty&; using key_equal = _Tr; +#if _HAS_CXX20 && defined(__EDG__) // TRANSITION, DevCom-10678753 + template + static constexpr bool _Supports_transparency = false; +#endif // ^^^ workaround ^^^ + _Hset_traits() = default; _Hset_traits(const _Tr& _Traits) noexcept(_STD is_nothrow_copy_constructible_v<_Tr>) : _Tr(_Traits) {} diff --git a/stl/inc/list b/stl/inc/list index ccc49ff24..84160362f 100644 --- a/stl/inc/list +++ b/stl/inc/list @@ -1864,8 +1864,7 @@ list(_Iter, _Iter, _Alloc = _Alloc()) -> list<_Iter_value_t<_Iter>, _Alloc>; #endif // _HAS_CXX17 #if _HAS_CXX23 -template <_RANGES input_range _Rng, class _Alloc = allocator<_RANGES range_value_t<_Rng>>, - enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc = allocator<_RANGES range_value_t<_Rng>>> list(from_range_t, _Rng&&, _Alloc = _Alloc()) -> list<_RANGES range_value_t<_Rng>, _Alloc>; #endif // _HAS_CXX23 diff --git a/stl/inc/map b/stl/inc/map index a8b764723..ecb13ccb9 100644 --- a/stl/inc/map +++ b/stl/inc/map @@ -385,12 +385,12 @@ map(initializer_list>, _Alloc) -> map<_Kty, _Ty, less<_Kty>, _Al #if _HAS_CXX23 template <_RANGES input_range _Rng, class _Pr = less<_Range_key_type<_Rng>>, - class _Alloc = allocator<_Range_to_alloc_type<_Rng>>, - enable_if_t>, _Is_allocator<_Alloc>>, int> = 0> + _Allocator_for_container _Alloc = allocator<_Range_to_alloc_type<_Rng>>> + requires (!_Allocator_for_container<_Pr>) map(from_range_t, _Rng&&, _Pr = _Pr(), _Alloc = _Alloc()) -> map<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, _Pr, _Alloc>; -template <_RANGES input_range _Rng, class _Alloc, enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc> map(from_range_t, _Rng&&, _Alloc) -> map<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, less<_Range_key_type<_Rng>>, _Alloc>; #endif // _HAS_CXX23 @@ -616,12 +616,12 @@ multimap(initializer_list>, _Alloc) -> multimap<_Kty, _Ty, less< #if _HAS_CXX23 template <_RANGES input_range _Rng, class _Pr = less<_Range_key_type<_Rng>>, - class _Alloc = allocator<_Range_to_alloc_type<_Rng>>, - enable_if_t>, _Is_allocator<_Alloc>>, int> = 0> + _Allocator_for_container _Alloc = allocator<_Range_to_alloc_type<_Rng>>> + requires (!_Allocator_for_container<_Pr>) multimap(from_range_t, _Rng&&, _Pr = _Pr(), _Alloc = _Alloc()) -> multimap<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, _Pr, _Alloc>; -template <_RANGES input_range _Rng, class _Alloc, enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc> multimap(from_range_t, _Rng&&, _Alloc) -> multimap<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, less<_Range_key_type<_Rng>>, _Alloc>; #endif // _HAS_CXX23 diff --git a/stl/inc/queue b/stl/inc/queue index 39f224afa..b61ce2500 100644 --- a/stl/inc/queue +++ b/stl/inc/queue @@ -50,7 +50,7 @@ public: : c(_STD move(_Cont)) {} #if _HAS_CXX23 - template , int> = 0> + template <_Iterator_for_container _InIt> queue(_InIt _First, _InIt _Last) noexcept(is_nothrow_constructible_v<_Container, _InIt, _InIt>) // strengthened : c(_STD move(_First), _STD move(_Last)) {} @@ -79,8 +79,8 @@ public: : c(_STD move(_Right.c), _Al) {} #if _HAS_CXX23 - template , uses_allocator<_Container, _Alloc>>, int> = 0> + template <_Iterator_for_container _InIt, class _Alloc> + requires uses_allocator_v<_Container, _Alloc> queue(_InIt _First, _InIt _Last, const _Alloc& _Al) noexcept( is_nothrow_constructible_v<_Container, _InIt, _InIt, const _Alloc&>) // strengthened : c(_STD move(_First), _STD move(_Last), _Al) {} @@ -169,12 +169,10 @@ queue(_Container, _Alloc) -> queue; #endif // _HAS_CXX17 #if _HAS_CXX23 -template >, - enable_if_t, _Is_allocator<_Alloc>>, int> = 0> +template <_Iterator_for_container _InIt, _Allocator_for_container _Alloc = allocator<_Iter_value_t<_InIt>>> queue(_InIt, _InIt, _Alloc = _Alloc()) -> queue<_Iter_value_t<_InIt>, deque<_Iter_value_t<_InIt>, _Alloc>>; -template <_RANGES input_range _Rng, class _Alloc = allocator<_RANGES range_value_t<_Rng>>, - enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc = allocator<_RANGES range_value_t<_Rng>>> queue(from_range_t, _Rng&&, _Alloc = _Alloc()) -> queue<_RANGES range_value_t<_Rng>, deque<_RANGES range_value_t<_Rng>, _Alloc>>; #endif // _HAS_CXX23 @@ -345,15 +343,15 @@ public: } #if _HAS_CXX23 - template <_Container_compatible_range<_Ty> _Rng, class _Alloc, - enable_if_t, int> = 0> + template <_Container_compatible_range<_Ty> _Rng, class _Alloc> + requires uses_allocator_v<_Container, _Alloc> priority_queue(from_range_t, _Rng&& _Range, const _Pr& _Pred, const _Alloc& _Al) : c(_RANGES to<_Container>(_STD forward<_Rng>(_Range), _Al)), comp(_Pred) { _Make_heap(); } - template <_Container_compatible_range<_Ty> _Rng, class _Alloc, - enable_if_t, int> = 0> + template <_Container_compatible_range<_Ty> _Rng, class _Alloc> + requires uses_allocator_v<_Container, _Alloc> priority_queue(from_range_t, _Rng&& _Range, const _Alloc& _Al) : c(_RANGES to<_Container>(_STD forward<_Rng>(_Range), _Al)), comp() { _Make_heap(); diff --git a/stl/inc/set b/stl/inc/set index 08a60f028..44bb78db0 100644 --- a/stl/inc/set +++ b/stl/inc/set @@ -196,11 +196,11 @@ set(initializer_list<_Kty>, _Alloc) -> set<_Kty, less<_Kty>, _Alloc>; #if _HAS_CXX23 template <_RANGES input_range _Rng, class _Pr = less<_RANGES range_value_t<_Rng>>, - class _Alloc = allocator<_RANGES range_value_t<_Rng>>, - enable_if_t>, _Is_allocator<_Alloc>>, int> = 0> + _Allocator_for_container _Alloc = allocator<_RANGES range_value_t<_Rng>>> + requires (!_Allocator_for_container<_Pr>) set(from_range_t, _Rng&&, _Pr = _Pr(), _Alloc = _Alloc()) -> set<_RANGES range_value_t<_Rng>, _Pr, _Alloc>; -template <_RANGES input_range _Rng, class _Alloc, enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc> set(from_range_t, _Rng&&, _Alloc) -> set<_RANGES range_value_t<_Rng>, less<_RANGES range_value_t<_Rng>>, _Alloc>; #endif // _HAS_CXX23 #endif // _HAS_CXX17 @@ -410,11 +410,11 @@ multiset(initializer_list<_Kty>, _Alloc) -> multiset<_Kty, less<_Kty>, _Alloc>; #if _HAS_CXX23 template <_RANGES input_range _Rng, class _Pr = less<_RANGES range_value_t<_Rng>>, - class _Alloc = allocator<_RANGES range_value_t<_Rng>>, - enable_if_t>, _Is_allocator<_Alloc>>, int> = 0> + _Allocator_for_container _Alloc = allocator<_RANGES range_value_t<_Rng>>> + requires (!_Allocator_for_container<_Pr>) multiset(from_range_t, _Rng&&, _Pr = _Pr(), _Alloc = _Alloc()) -> multiset<_RANGES range_value_t<_Rng>, _Pr, _Alloc>; -template <_RANGES input_range _Rng, class _Alloc, enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc> multiset(from_range_t, _Rng&&, _Alloc) -> multiset<_RANGES range_value_t<_Rng>, less<_RANGES range_value_t<_Rng>>, _Alloc>; #endif // _HAS_CXX23 diff --git a/stl/inc/sstream b/stl/inc/sstream index 4d44166fa..338f3f41c 100644 --- a/stl/inc/sstream +++ b/stl/inc/sstream @@ -230,8 +230,7 @@ public: } #if _HAS_CXX20 - template - requires _Is_allocator<_Alloc2>::value + template <_Allocator_for_container _Alloc2> _NODISCARD basic_string<_Elem, _Traits, _Alloc2> str(const _Alloc2& _Al) const { return basic_string<_Elem, _Traits, _Alloc2>{view(), _Al}; } @@ -694,8 +693,7 @@ public: } #if _HAS_CXX20 - template - requires _Is_allocator<_Alloc2>::value + template <_Allocator_for_container _Alloc2> _NODISCARD basic_string<_Elem, _Traits, _Alloc2> str(const _Alloc2& _Al) const { return _Stringbuffer.str(_Al); } @@ -814,7 +812,7 @@ public: } #if _HAS_CXX20 - template ::value, int> = 0> + template <_Allocator_for_container _Alloc2> _NODISCARD basic_string<_Elem, _Traits, _Alloc2> str(const _Alloc2& _Al) const { return _Stringbuffer.str(_Al); } @@ -939,7 +937,7 @@ public: } #if _HAS_CXX20 - template ::value, int> = 0> + template <_Allocator_for_container _Alloc2> _NODISCARD basic_string<_Elem, _Traits, _Alloc2> str(const _Alloc2& _Al) const { return _Stringbuffer.str(_Al); } diff --git a/stl/inc/stack b/stl/inc/stack index 6dd94f110..e98e69dee 100644 --- a/stl/inc/stack +++ b/stl/inc/stack @@ -43,7 +43,7 @@ public: : c(_STD move(_Cont)) {} #if _HAS_CXX23 - template , int> = 0> + template <_Iterator_for_container _InIt> stack(_InIt _First, _InIt _Last) noexcept(is_nothrow_constructible_v<_Container, _InIt, _InIt>) // strengthened : c(_STD move(_First), _STD move(_Last)) {} @@ -72,8 +72,8 @@ public: : c(_STD move(_Right.c), _Al) {} #if _HAS_CXX23 - template , uses_allocator<_Container, _Alloc>>, int> = 0> + template <_Iterator_for_container _InIt, class _Alloc> + requires uses_allocator_v<_Container, _Alloc> stack(_InIt _First, _InIt _Last, const _Alloc& _Al) noexcept( is_nothrow_constructible_v<_Container, _InIt, _InIt, const _Alloc&>) // strengthened : c(_STD move(_First), _STD move(_Last), _Al) {} @@ -154,14 +154,13 @@ stack(_Container, _Alloc) -> stack; #endif // _HAS_CXX17 #if _HAS_CXX23 -template >, - enable_if_t, _Is_allocator<_Alloc>>, int> = 0> +template <_Iterator_for_container _InIt, _Allocator_for_container _Alloc = allocator<_Iter_value_t<_InIt>>> stack(_InIt, _InIt, _Alloc = _Alloc()) -> stack<_Iter_value_t<_InIt>, deque<_Iter_value_t<_InIt>, _Alloc>>; template <_RANGES input_range _Rng> stack(from_range_t, _Rng&&) -> stack<_RANGES range_value_t<_Rng>>; -template <_RANGES input_range _Rng, class _Alloc, enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc> stack(from_range_t, _Rng&&, _Alloc) -> stack<_RANGES range_value_t<_Rng>, deque<_RANGES range_value_t<_Rng>, _Alloc>>; #endif // _HAS_CXX23 diff --git a/stl/inc/unordered_map b/stl/inc/unordered_map index bff9e8d6a..d0f0b2aa9 100644 --- a/stl/inc/unordered_map +++ b/stl/inc/unordered_map @@ -497,22 +497,22 @@ unordered_map(initializer_list>, _Guide_size_type_t<_Alloc>, _Ha -> unordered_map<_Kty, _Ty, _Hasher, equal_to<_Kty>, _Alloc>; #if _HAS_CXX23 -template <_RANGES input_range _Rng, class _Hasher = hash<_Range_key_type<_Rng>>, - class _Keyeq = equal_to<_Range_key_type<_Rng>>, class _Alloc = allocator<_Range_to_alloc_type<_Rng>>, - enable_if_t, negation<_Is_allocator<_Keyeq>>, _Is_allocator<_Alloc>>, int> = 0> +template <_RANGES input_range _Rng, _Hasher_for_container _Hasher = hash<_Range_key_type<_Rng>>, + class _Keyeq = equal_to<_Range_key_type<_Rng>>, + _Allocator_for_container _Alloc = allocator<_Range_to_alloc_type<_Rng>>> + requires (!_Allocator_for_container<_Keyeq>) unordered_map(from_range_t, _Rng&&, _Guide_size_type_t<_Alloc> = 0, _Hasher = _Hasher(), _Keyeq = _Keyeq(), _Alloc = _Alloc()) -> unordered_map<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, _Hasher, _Keyeq, _Alloc>; -template <_RANGES input_range _Rng, class _Alloc, enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc> unordered_map(from_range_t, _Rng&&, _Guide_size_type_t<_Alloc>, _Alloc) -> unordered_map<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, hash<_Range_key_type<_Rng>>, equal_to<_Range_key_type<_Rng>>, _Alloc>; -template <_RANGES input_range _Rng, class _Alloc, enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc> unordered_map(from_range_t, _Rng&&, _Alloc) -> unordered_map<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, hash<_Range_key_type<_Rng>>, equal_to<_Range_key_type<_Rng>>, _Alloc>; -template <_RANGES input_range _Rng, class _Hasher, class _Alloc, - enable_if_t, _Is_allocator<_Alloc>>, int> = 0> +template <_RANGES input_range _Rng, _Hasher_for_container _Hasher, _Allocator_for_container _Alloc> unordered_map(from_range_t, _Rng&&, _Guide_size_type_t<_Alloc>, _Hasher, _Alloc) -> unordered_map<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, _Hasher, equal_to<_Range_key_type<_Rng>>, _Alloc>; #endif // _HAS_CXX23 @@ -867,23 +867,23 @@ unordered_multimap(initializer_list>, _Guide_size_type_t<_Alloc> -> unordered_multimap<_Kty, _Ty, _Hasher, equal_to<_Kty>, _Alloc>; #if _HAS_CXX23 -template <_RANGES input_range _Rng, class _Hasher = hash<_Range_key_type<_Rng>>, - class _Keyeq = equal_to<_Range_key_type<_Rng>>, class _Alloc = allocator<_Range_to_alloc_type<_Rng>>, - enable_if_t, negation<_Is_allocator<_Keyeq>>, _Is_allocator<_Alloc>>, int> = 0> +template <_RANGES input_range _Rng, _Hasher_for_container _Hasher = hash<_Range_key_type<_Rng>>, + class _Keyeq = equal_to<_Range_key_type<_Rng>>, + _Allocator_for_container _Alloc = allocator<_Range_to_alloc_type<_Rng>>> + requires (!_Allocator_for_container<_Keyeq>) unordered_multimap(from_range_t, _Rng&&, _Guide_size_type_t<_Alloc> = 0, _Hasher = _Hasher(), _Keyeq = _Keyeq(), _Alloc = _Alloc()) -> unordered_multimap<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, _Hasher, _Keyeq, _Alloc>; -template <_RANGES input_range _Rng, class _Alloc, enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc> unordered_multimap(from_range_t, _Rng&&, _Guide_size_type_t<_Alloc>, _Alloc) -> unordered_multimap<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, hash<_Range_key_type<_Rng>>, equal_to<_Range_key_type<_Rng>>, _Alloc>; -template <_RANGES input_range _Rng, class _Alloc, enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc> unordered_multimap(from_range_t, _Rng&&, _Alloc) -> unordered_multimap<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, hash<_Range_key_type<_Rng>>, equal_to<_Range_key_type<_Rng>>, _Alloc>; -template <_RANGES input_range _Rng, class _Hasher, class _Alloc, - enable_if_t, _Is_allocator<_Alloc>>, int> = 0> +template <_RANGES input_range _Rng, _Hasher_for_container _Hasher, _Allocator_for_container _Alloc> unordered_multimap(from_range_t, _Rng&&, _Guide_size_type_t<_Alloc>, _Hasher, _Alloc) -> unordered_multimap<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, _Hasher, equal_to<_Range_key_type<_Rng>>, _Alloc>; diff --git a/stl/inc/unordered_set b/stl/inc/unordered_set index d9a390c25..e94e2b680 100644 --- a/stl/inc/unordered_set +++ b/stl/inc/unordered_set @@ -353,22 +353,22 @@ unordered_set(initializer_list<_Kty>, _Guide_size_type_t<_Alloc>, _Hasher, _Allo -> unordered_set<_Kty, _Hasher, equal_to<_Kty>, _Alloc>; #if _HAS_CXX23 -template <_RANGES input_range _Rng, class _Hasher = hash<_RANGES range_value_t<_Rng>>, - class _Keyeq = equal_to<_RANGES range_value_t<_Rng>>, class _Alloc = allocator<_RANGES range_value_t<_Rng>>, - enable_if_t, negation<_Is_allocator<_Keyeq>>, _Is_allocator<_Alloc>>, int> = 0> +template <_RANGES input_range _Rng, _Hasher_for_container _Hasher = hash<_RANGES range_value_t<_Rng>>, + class _Keyeq = equal_to<_RANGES range_value_t<_Rng>>, + _Allocator_for_container _Alloc = allocator<_RANGES range_value_t<_Rng>>> + requires (!_Allocator_for_container<_Keyeq>) unordered_set(from_range_t, _Rng&&, _Guide_size_type_t<_Alloc> = 0, _Hasher = _Hasher(), _Keyeq = _Keyeq(), _Alloc = _Alloc()) -> unordered_set<_RANGES range_value_t<_Rng>, _Hasher, _Keyeq, _Alloc>; -template <_RANGES input_range _Rng, class _Alloc, enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc> unordered_set(from_range_t, _Rng&&, _Guide_size_type_t<_Alloc>, _Alloc) -> unordered_set<_RANGES range_value_t<_Rng>, hash<_RANGES range_value_t<_Rng>>, equal_to<_RANGES range_value_t<_Rng>>, _Alloc>; -template <_RANGES input_range _Rng, class _Alloc, enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc> unordered_set(from_range_t, _Rng&&, _Alloc) -> unordered_set<_RANGES range_value_t<_Rng>, hash<_RANGES range_value_t<_Rng>>, equal_to<_RANGES range_value_t<_Rng>>, _Alloc>; -template <_RANGES input_range _Rng, class _Hasher, class _Alloc, - enable_if_t, _Is_allocator<_Alloc>>, int> = 0> +template <_RANGES input_range _Rng, _Hasher_for_container _Hasher, _Allocator_for_container _Alloc> unordered_set(from_range_t, _Rng&&, _Guide_size_type_t<_Alloc>, _Hasher, _Alloc) -> unordered_set<_RANGES range_value_t<_Rng>, _Hasher, equal_to<_RANGES range_value_t<_Rng>>, _Alloc>; #endif // _HAS_CXX23 @@ -696,23 +696,23 @@ unordered_multiset(initializer_list<_Kty>, _Guide_size_type_t<_Alloc>, _Hasher, -> unordered_multiset<_Kty, _Hasher, equal_to<_Kty>, _Alloc>; #if _HAS_CXX23 -template <_RANGES input_range _Rng, class _Hasher = hash<_RANGES range_value_t<_Rng>>, - class _Keyeq = equal_to<_RANGES range_value_t<_Rng>>, class _Alloc = allocator<_RANGES range_value_t<_Rng>>, - enable_if_t, negation<_Is_allocator<_Keyeq>>, _Is_allocator<_Alloc>>, int> = 0> +template <_RANGES input_range _Rng, _Hasher_for_container _Hasher = hash<_RANGES range_value_t<_Rng>>, + class _Keyeq = equal_to<_RANGES range_value_t<_Rng>>, + _Allocator_for_container _Alloc = allocator<_RANGES range_value_t<_Rng>>> + requires (!_Allocator_for_container<_Keyeq>) unordered_multiset(from_range_t, _Rng&&, _Guide_size_type_t<_Alloc> = 0, _Hasher = _Hasher(), _Keyeq = _Keyeq(), _Alloc = _Alloc()) -> unordered_multiset<_RANGES range_value_t<_Rng>, _Hasher, _Keyeq, _Alloc>; -template <_RANGES input_range _Rng, class _Alloc, enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc> unordered_multiset(from_range_t, _Rng&&, _Guide_size_type_t<_Alloc>, _Alloc) -> unordered_multiset<_RANGES range_value_t<_Rng>, hash<_RANGES range_value_t<_Rng>>, equal_to<_RANGES range_value_t<_Rng>>, _Alloc>; -template <_RANGES input_range _Rng, class _Alloc, enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc> unordered_multiset(from_range_t, _Rng&&, _Alloc) -> unordered_multiset<_RANGES range_value_t<_Rng>, hash<_RANGES range_value_t<_Rng>>, equal_to<_RANGES range_value_t<_Rng>>, _Alloc>; -template <_RANGES input_range _Rng, class _Hasher, class _Alloc, - enable_if_t, _Is_allocator<_Alloc>>, int> = 0> +template <_RANGES input_range _Rng, _Hasher_for_container _Hasher, _Allocator_for_container _Alloc> unordered_multiset(from_range_t, _Rng&&, _Guide_size_type_t<_Alloc>, _Hasher, _Alloc) -> unordered_multiset<_RANGES range_value_t<_Rng>, _Hasher, equal_to<_RANGES range_value_t<_Rng>>, _Alloc>; #endif // _HAS_CXX23 diff --git a/stl/inc/vector b/stl/inc/vector index e2d7e0cc6..f6d6cf430 100644 --- a/stl/inc/vector +++ b/stl/inc/vector @@ -2208,8 +2208,7 @@ vector(_Iter, _Iter, _Alloc = _Alloc()) -> vector<_Iter_value_t<_Iter>, _Alloc>; #endif // _HAS_CXX17 #if _HAS_CXX23 -template <_RANGES input_range _Rng, class _Alloc = allocator<_RANGES range_value_t<_Rng>>, - enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc = allocator<_RANGES range_value_t<_Rng>>> vector(from_range_t, _Rng&&, _Alloc = _Alloc()) -> vector<_RANGES range_value_t<_Rng>, _Alloc>; #endif // _HAS_CXX23 diff --git a/stl/inc/xhash b/stl/inc/xhash index 20f884eef..664b127fc 100644 --- a/stl/inc/xhash +++ b/stl/inc/xhash @@ -93,17 +93,22 @@ _STD_END #endif // _SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS _STD_BEGIN -template +template struct _Uhash_choose_transparency { // transparency selector for non-transparent hashed containers template using _Deduce_key = const _Kty&; + +#if _HAS_CXX20 && defined(__EDG__) // TRANSITION, DevCom-10678753 + template + static constexpr bool _Supports_transparency = false; +#endif // ^^^ workaround ^^^ }; #if _HAS_CXX20 template -struct _Uhash_choose_transparency<_Kty, _Hasher, _Keyeq, - enable_if_t, _Is_transparent<_Keyeq>>>> { + requires _Is_transparent_v<_Hasher> && _Is_transparent_v<_Keyeq> +struct _Uhash_choose_transparency<_Kty, _Hasher, _Keyeq> { // transparency selector for transparent hashed containers template using _Deduce_key = const _Keyty&; @@ -1137,8 +1142,8 @@ public: } #if _HAS_CXX23 - template , int> = 0> + template + requires (_Traits::template _Supports_transparency<_Hash, _Kx>) size_type erase(_Kx&& _Keyval) noexcept(noexcept(_Erase(_Keyval))) /* strengthened */ { return _Erase(_Keyval); } @@ -1347,8 +1352,8 @@ public: } #if _HAS_CXX23 - template , int> = 0> + template + requires (_Traits::template _Supports_transparency<_Hash, _Kx>) node_type extract(_Kx&& _Keyval) { const auto _Ptr = _Extract(_Keyval); if (!_Ptr) { @@ -1967,9 +1972,17 @@ protected: }; #if _HAS_CXX17 -// For constraining deduction guides (N4950 [unord.req.general]/243.3) +// For constraining deduction guides (N4981 [unord.req.general]/248.3) +#if _HAS_CXX23 +template +concept _Hasher_for_container = !integral<_Hasher> && !_Allocator_for_container<_Hasher>; + +template +using _Is_hasher = bool_constant<_Hasher_for_container<_Hasher>>; +#else // ^^^ _HAS_CXX23 / !_HAS_CXX23 vvv template using _Is_hasher = negation, _Is_allocator<_Hasher>>>; +#endif // ^^^ !_HAS_CXX23 ^^^ #endif // _HAS_CXX17 template diff --git a/stl/inc/xstring b/stl/inc/xstring index b048c1f2f..ed4026cff 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -3106,8 +3106,7 @@ basic_string(basic_string_view<_Elem, _Traits>, _Guide_size_type_t<_Alloc>, _Gui const _Alloc& = _Alloc()) -> basic_string<_Elem, _Traits, _Alloc>; #if _HAS_CXX23 -template <_RANGES input_range _Rng, class _Alloc = allocator<_RANGES range_value_t<_Rng>>, - enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc = allocator<_RANGES range_value_t<_Rng>>> basic_string(from_range_t, _Rng&&, _Alloc = _Alloc()) -> basic_string<_RANGES range_value_t<_Rng>, char_traits<_RANGES range_value_t<_Rng>>, _Alloc>; #endif // _HAS_CXX23 diff --git a/stl/inc/xtree b/stl/inc/xtree index 5d970ede4..5b7c60bdb 100644 --- a/stl/inc/xtree +++ b/stl/inc/xtree @@ -1335,10 +1335,9 @@ public: } #if _HAS_CXX23 - template , - negation, is_convertible<_Kx, iterator>>>>, - int> = 0> + template + requires _Is_transparent_v + && (!is_convertible_v<_Kx, const_iterator>) && (!is_convertible_v<_Kx, iterator>) size_type erase(_Kx&& _Keyval) noexcept(noexcept(_Eqrange(_Keyval))) /* strengthened */ { return _Erase(_Eqrange(_Keyval)); } @@ -1390,7 +1389,8 @@ public: return _Lower_bound_duplicate(_Find_lower_bound(_Keyval)._Bound, _Keyval); } - template , int> = 0> + template + requires _Is_transparent_v _NODISCARD bool contains(const _Other& _Keyval) const { return _Lower_bound_duplicate(_Find_lower_bound(_Keyval)._Bound, _Keyval); } @@ -1743,10 +1743,9 @@ public: } #if _HAS_CXX23 - template , - negation, is_convertible<_Kx, iterator>>>>, - int> = 0> + template + requires _Is_transparent_v + && (!is_convertible_v<_Kx, const_iterator>) && (!is_convertible_v<_Kx, iterator>) node_type extract(_Kx&& _Keyval) { const const_iterator _Where = find(_Keyval); if (_Where == end()) { diff --git a/stl/inc/xutility b/stl/inc/xutility index ee83e903b..988196930 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -1205,6 +1205,16 @@ using _Common_diff_t = common_type_t<_Iter_diff_t<_Iters>...>; template using _Iter_cat_t = typename iterator_traits<_Iter>::iterator_category; +#if _HAS_CXX20 +template +concept _Iterator_for_container = requires { typename _Iter_cat_t<_Ty>; }; + +template +constexpr bool _Is_iterator_v = _Iterator_for_container<_Ty>; + +template +struct _Is_iterator : bool_constant<_Iterator_for_container<_Ty>> {}; +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv template constexpr bool _Is_iterator_v = false; @@ -1213,6 +1223,7 @@ constexpr bool _Is_iterator_v<_Ty, void_t<_Iter_cat_t<_Ty>>> = true; template struct _Is_iterator : bool_constant<_Is_iterator_v<_Ty>> {}; +#endif // ^^^ !_HAS_CXX20 ^^^ template constexpr bool _Is_cpp17_input_iter_v = is_convertible_v<_Iter_cat_t<_Iter>, input_iterator_tag>; @@ -1423,6 +1434,17 @@ constexpr void _Seek_wrapped(_Iter& _It, _UIter&& _UIt) { } #if _HAS_CXX17 +#if _HAS_CXX20 +// detects whether _Ty resembles an allocator, N4981 [container.reqmts]/69 +template +concept _Allocator_for_container = requires(_Ty& _Alloc) { + typename _Ty::value_type; + _Alloc.deallocate(_Alloc.allocate(size_t{1}), size_t{1}); +}; + +template +struct _Is_allocator : bool_constant<_Allocator_for_container<_Ty>> {}; +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv template struct _Is_allocator : false_type {}; // selected when _Ty can't possibly be an allocator @@ -1430,6 +1452,7 @@ template struct _Is_allocator<_Ty, void_t().deallocate( _STD declval<_Ty&>().allocate(size_t{1}), size_t{1}))>> : true_type {}; // selected when _Ty resembles an allocator, N4950 [container.reqmts]/69 +#endif // ^^^ !_HAS_CXX20 ^^^ // deduction guide utilities (N4950 [associative.general]/2) template