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

Fixes #135351

This PR update CATD guides to associative containers (`std::map`,
`std::multimap`, `std::unordered_map`, `std::unordered_multimap`,
`std::flat_map`, `std::flat_multimap`).

- Updated template alias for deduction guides for the relevant
associative containers.
- Added a new test to verify the deduction guides with `std::map`,
`std::multimap`, `std::unordered_map`, `std::unordered_multimap`,
`std::flat_map`, `std::flat_multimap`.
This commit is contained in:
Ksar
2025-05-30 15:17:06 +08:00
committed by GitHub
parent df712f588c
commit b71255705b
13 changed files with 223 additions and 1 deletions

View File

@@ -22,6 +22,7 @@
#include <__fwd/pair.h>
#include <__iterator/incrementable_traits.h>
#include <__iterator/readable_traits.h>
#include <__tuple/tuple_element.h>
#include <__type_traits/common_reference.h>
#include <__type_traits/conditional.h>
#include <__type_traits/detected_or.h>
@@ -466,6 +467,18 @@ using __has_exactly_bidirectional_iterator_category _LIBCPP_NODEBUG =
template <class _InputIterator>
using __iter_value_type _LIBCPP_NODEBUG = typename iterator_traits<_InputIterator>::value_type;
#if _LIBCPP_STD_VER >= 23
template <class _InputIterator>
using __iter_key_type _LIBCPP_NODEBUG = remove_const_t<tuple_element_t<0, __iter_value_type<_InputIterator>>>;
template <class _InputIterator>
using __iter_mapped_type _LIBCPP_NODEBUG = tuple_element_t<1, __iter_value_type<_InputIterator>>;
template <class _InputIterator>
using __iter_to_alloc_type _LIBCPP_NODEBUG =
pair<const tuple_element_t<0, __iter_value_type<_InputIterator>>,
tuple_element_t<1, __iter_value_type<_InputIterator>>>;
#else
template <class _InputIterator>
using __iter_key_type _LIBCPP_NODEBUG =
__remove_const_t<typename iterator_traits<_InputIterator>::value_type::first_type>;
@@ -477,6 +490,7 @@ template <class _InputIterator>
using __iter_to_alloc_type _LIBCPP_NODEBUG =
pair<const typename iterator_traits<_InputIterator>::value_type::first_type,
typename iterator_traits<_InputIterator>::value_type::second_type>;
#endif // _LIBCPP_STD_VER >= 23
template <class _Iter>
using __iterator_category_type _LIBCPP_NODEBUG = typename iterator_traits<_Iter>::iterator_category;

View File

@@ -40,7 +40,10 @@
#include <climits> // INT_MAX
#include <functional>
#include <map>
#include <utility>
#include <tuple>
#include <type_traits>
#include <vector>
#include "deduction_guides_sfinae_checks.h"
#include "test_allocator.h"
@@ -189,6 +192,23 @@ int main(int, char**) {
static_assert(std::is_same_v<decltype(c), std::map<int, long, DefaultComp, Alloc>>);
}
}
{
std::vector<std::pair<const int, float>> pair_vec = {{1, 1.1f}, {2, 2.2f}, {3, 3.3f}};
std::map m1(pair_vec.begin(), pair_vec.end());
ASSERT_SAME_TYPE(decltype(m1), std::map<int, float>);
std::vector<std::tuple<int, double>> tuple_vec = {{10, 1.1}, {20, 2.2}, {30, 3.3}};
std::map m2(tuple_vec.begin(), tuple_vec.end());
ASSERT_SAME_TYPE(decltype(m2), std::map<int, double>);
std::vector<std::array<long, 2>> array_vec = {{100L, 101L}, {200L, 201L}, {300L, 301L}};
std::map m3(array_vec.begin(), array_vec.end());
ASSERT_SAME_TYPE(decltype(m3), std::map<long, long>);
std::vector<std::pair<int, char>> non_const_key_pair_vec = {{5, 'a'}, {6, 'b'}};
std::map m4(non_const_key_pair_vec.begin(), non_const_key_pair_vec.end());
ASSERT_SAME_TYPE(decltype(m4), std::map<int, char>);
}
#endif
AssociativeContainerDeductionGuidesSfinaeAway<std::map, std::map<int, long>>();

View File

@@ -26,9 +26,11 @@
// map(initializer_list<Key>, Allocator)
// -> map<Key, less<Key>, Allocator>;
#include <array>
#include <climits> // INT_MAX
#include <functional>
#include <map>
#include <tuple>
#include <type_traits>
struct NotAnAllocator {
@@ -101,6 +103,17 @@ int main(int, char**) {
std::map m(PC{1, 1L});
// expected-error-re@-1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}map'}}
}
{
// cannot deduce from tuple-like objects without proper iterator
std::tuple<int, double> t{1, 2.0};
std::map m(t);
// expected-error-re@-1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}map'}}
}
{
// cannot deduce from array-like objects without proper iterator
std::array<int, 2> arr{1, 2};
std::map m(arr);
// expected-error-re@-1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}map'}}
}
return 0;
}

View File

@@ -40,7 +40,10 @@
#include <climits> // INT_MAX
#include <functional>
#include <map>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
#include "deduction_guides_sfinae_checks.h"
#include "test_allocator.h"
@@ -189,6 +192,24 @@ int main(int, char**) {
static_assert(std::is_same_v<decltype(c), std::multimap<int, long, DefaultComp, Alloc>>);
}
}
{
std::vector<std::pair<const int, float>> pair_vec = {{1, 1.1f}, {2, 2.2f}, {3, 3.3f}};
std::multimap mm1(pair_vec.begin(), pair_vec.end());
ASSERT_SAME_TYPE(decltype(mm1), std::multimap<int, float>);
std::vector<std::tuple<int, double>> tuple_vec = {{10, 1.1}, {20, 2.2}, {30, 3.3}};
std::multimap mm2(tuple_vec.begin(), tuple_vec.end());
ASSERT_SAME_TYPE(decltype(mm2), std::multimap<int, double>);
std::vector<std::array<long, 2>> array_vec = {{100L, 101L}, {200L, 201L}, {300L, 301L}};
std::multimap mm3(array_vec.begin(), array_vec.end());
ASSERT_SAME_TYPE(decltype(mm3), std::multimap<long, long>);
// Check deduction with non-const key in input pair
std::vector<std::pair<int, char>> non_const_key_pair_vec = {{5, 'a'}, {6, 'b'}};
std::multimap mm4(non_const_key_pair_vec.begin(), non_const_key_pair_vec.end());
ASSERT_SAME_TYPE(decltype(mm4), std::multimap<int, char>);
}
#endif
AssociativeContainerDeductionGuidesSfinaeAway<std::multimap, std::multimap<int, long>>();

View File

@@ -26,9 +26,11 @@
// multimap(initializer_list<Key>, Allocator)
// -> multimap<Key, less<Key>, Allocator>;
#include <array>
#include <climits> // INT_MAX
#include <functional>
#include <map>
#include <tuple>
#include <type_traits>
struct NotAnAllocator {
@@ -101,6 +103,18 @@ int main(int, char**) {
std::multimap m(PC{1, 1L});
// expected-error-re@-1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}multimap'}}
}
{
// cannot deduce from tuple-like objects without proper iterator
std::tuple<int, double> t{1, 2.0};
std::multimap m(t);
// expected-error-re@-1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}multimap'}}
}
{
// cannot deduce from array-like objects without proper iterator
std::array<int, 2> arr{1, 2};
std::multimap m(arr);
// expected-error-re@-1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}multimap'}}
}
return 0;
}

View File

@@ -11,6 +11,7 @@
// <flat_map>
#include <algorithm>
#include <array>
#include <cassert>
#include <climits>
#include <deque>
@@ -19,6 +20,7 @@
#include <flat_map>
#include <functional>
#include <ranges>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
@@ -335,6 +337,24 @@ int main(int, char**) {
test_from_range();
test_from_range_compare();
#if TEST_STD_VER >= 23
std::vector<std::pair<const int, float>> pair_vec = {{1, 1.1f}, {2, 2.2f}, {3, 3.3f}};
std::flat_map fm1(pair_vec.begin(), pair_vec.end());
ASSERT_SAME_TYPE(decltype(fm1), std::flat_map<int, float>);
std::vector<std::tuple<int, double>> tuple_vec = {{10, 1.1}, {20, 2.2}, {30, 3.3}};
std::flat_map fm2(tuple_vec.begin(), tuple_vec.end());
ASSERT_SAME_TYPE(decltype(fm2), std::flat_map<int, double>);
std::vector<std::array<long, 2>> array_vec = {{100L, 101L}, {200L, 201L}, {300L, 301L}};
std::flat_map fm3(array_vec.begin(), array_vec.end());
ASSERT_SAME_TYPE(decltype(fm3), std::flat_map<long, long>);
std::vector<std::pair<int, char>> non_const_key_pair_vec = {{5, 'a'}, {6, 'b'}};
std::flat_map fm4(non_const_key_pair_vec.begin(), non_const_key_pair_vec.end());
ASSERT_SAME_TYPE(decltype(fm4), std::flat_map<int, char>);
#endif
AssociativeContainerDeductionGuidesSfinaeAway<std::flat_map, std::flat_map<int, short>>();
return 0;

View File

@@ -12,9 +12,11 @@
// Test CTAD on cases where deduction should fail.
#include <array>
#include <flat_map>
#include <functional>
#include <utility>
#include <tuple>
using P = std::pair<int, long>;
using PC = std::pair<const int, long>;
@@ -50,4 +52,16 @@ void test() {
std::flat_map m(PC{1, 1L});
// expected-error-re@-1{{{{no viable constructor or deduction guide for deduction of template arguments of '.*flat_map'}}}}
}
{
// cannot deduce from tuple-like objects without proper iterator
std::tuple<int, double> t{1, 2.0};
std::flat_map m(t);
// expected-error-re@-1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}flat_map'}}
}
{
// cannot deduce from array-like objects without proper iterator
std::array<int, 2> arr{1, 2};
std::flat_map m(arr);
// expected-error-re@-1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}flat_map'}}
}
}

View File

@@ -11,6 +11,7 @@
// <flat_map>
#include <algorithm>
#include <array>
#include <cassert>
#include <climits>
#include <deque>
@@ -325,6 +326,24 @@ void test_from_range_compare() {
}
}
void test_tuple_like_deduction() {
std::vector<std::pair<const int, float>> pair_vec = {{1, 1.1f}, {2, 2.2f}, {3, 3.3f}};
std::flat_multimap fmm1(pair_vec.begin(), pair_vec.end());
ASSERT_SAME_TYPE(decltype(fmm1), std::flat_multimap<int, float>);
std::vector<std::tuple<int, double>> tuple_vec = {{10, 1.1}, {20, 2.2}, {30, 3.3}};
std::flat_multimap fmm2(tuple_vec.begin(), tuple_vec.end());
ASSERT_SAME_TYPE(decltype(fmm2), std::flat_multimap<int, double>);
std::vector<std::array<long, 2>> array_vec = {{100L, 101L}, {200L, 201L}, {300L, 301L}};
std::flat_multimap fmm3(array_vec.begin(), array_vec.end());
ASSERT_SAME_TYPE(decltype(fmm3), std::flat_multimap<long, long>);
std::vector<std::pair<int, char>> non_const_key_pair_vec = {{5, 'a'}, {6, 'b'}};
std::flat_multimap fmm4(non_const_key_pair_vec.begin(), non_const_key_pair_vec.end());
ASSERT_SAME_TYPE(decltype(fmm4), std::flat_multimap<int, char>);
}
int main(int, char**) {
// Each test function also tests the sorted_equivalent-prefixed and allocator-suffixed overloads.
test_copy();
@@ -336,6 +355,7 @@ int main(int, char**) {
test_initializer_list_compare();
test_from_range();
test_from_range_compare();
test_tuple_like_deduction();
AssociativeContainerDeductionGuidesSfinaeAway<std::flat_multimap, std::flat_multimap<int, short>>();

View File

@@ -12,8 +12,10 @@
// Test CTAD on cases where deduction should fail.
#include <array>
#include <flat_map>
#include <functional>
#include <tuple>
#include <utility>
struct NotAnAllocator {
@@ -54,4 +56,16 @@ void test() {
std::flat_multimap m(PC{1, 1L});
// expected-error-re@-1{{{{no viable constructor or deduction guide for deduction of template arguments of '.*flat_multimap'}}}}
}
{
// cannot deduce from tuple-like objects without proper iterator
std::tuple<int, double> t{1, 2.0};
std::flat_multimap m(t);
// expected-error-re@-1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}flat_multimap'}}
}
{
// cannot deduce from array-like objects without proper iterator
std::array<int, 2> arr{1, 2};
std::flat_multimap m(arr);
// expected-error-re@-1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}flat_multimap'}}
}
}

View File

@@ -82,8 +82,11 @@
#include <cassert>
#include <climits> // INT_MAX
#include <iterator>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include <vector>
#include "../../../test_compare.h"
#include "../../../test_hash.h"
@@ -311,6 +314,26 @@ int main(int, char**) {
static_assert(std::is_same_v<decltype(c), std::unordered_map<int, long, Hash, DefaultPred, Alloc>>);
}
}
{
std::vector<std::pair<const int, float>> pair_vec = {{1, 1.1f}, {2, 2.2f}, {3, 3.3f}};
std::unordered_map um1(pair_vec.begin(), pair_vec.end());
ASSERT_SAME_TYPE(decltype(um1), std::unordered_map<int, float>);
std::vector<std::tuple<int, double>> tuple_vec = {{10, 1.1}, {20, 2.2}, {30, 3.3}};
// Note: std::tuple needs a hash specialization to be used as a key in unordered containers.
// This static_assert only checks the deduced type.
std::unordered_map um2(tuple_vec.begin(), tuple_vec.end());
ASSERT_SAME_TYPE(decltype(um2), std::unordered_map<int, double>);
std::vector<std::array<long, 2>> array_vec = {{100L, 101L}, {200L, 201L}, {300L, 301L}};
// Note: std::array needs a hash specialization.
std::unordered_map um3(array_vec.begin(), array_vec.end());
ASSERT_SAME_TYPE(decltype(um3), std::unordered_map<long, long>);
std::vector<std::pair<int, char>> non_const_key_pair_vec = {{5, 'a'}, {6, 'b'}};
std::unordered_map um4(non_const_key_pair_vec.begin(), non_const_key_pair_vec.end());
ASSERT_SAME_TYPE(decltype(um4), std::unordered_map<int, char>);
}
#endif
UnorderedContainerDeductionGuidesSfinaeAway<std::unordered_map, std::unordered_map<int, long>>();

View File

@@ -56,7 +56,9 @@
// Allocator)
// -> unordered_map<Key, T, Hash, equal_to<Key>, Allocator>;
#include <array>
#include <functional>
#include <tuple>
#include <unordered_map>
int main(int, char**) {
@@ -101,6 +103,18 @@ int main(int, char**) {
std::unordered_map m(42, std::hash<int>(), std::allocator<P>());
// expected-error-re@-1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}unordered_map'}}
}
{
// cannot deduce from tuple-like objects without proper iterator
std::tuple<int, double> t{1, 2.0};
std::unordered_map m(t);
// expected-error-re@-1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}unordered_map'}}
}
{
// cannot deduce from array-like objects without proper iterator
std::array<int, 2> arr{1, 2};
std::unordered_map m(arr);
// expected-error-re@-1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}unordered_map'}}
}
return 0;
}

View File

@@ -81,8 +81,11 @@
#include <array>
#include <cassert>
#include <climits> // INT_MAX
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include <vector>
#include "../../../test_compare.h"
#include "../../../test_hash.h"
@@ -307,6 +310,24 @@ int main(int, char**) {
static_assert(std::is_same_v<decltype(c), std::unordered_multimap<int, long, Hash, DefaultPred, Alloc>>);
}
}
{
std::vector<std::pair<const int, float>> pair_vec = {{1, 1.1f}, {2, 2.2f}, {3, 3.3f}};
std::unordered_multimap umm1(pair_vec.begin(), pair_vec.end());
ASSERT_SAME_TYPE(decltype(umm1), std::unordered_multimap<int, float>);
std::vector<std::tuple<int, double>> tuple_vec = {{10, 1.1}, {20, 2.2}, {30, 3.3}};
std::unordered_multimap umm2(tuple_vec.begin(), tuple_vec.end());
ASSERT_SAME_TYPE(decltype(umm2), std::unordered_multimap<int, double>);
std::vector<std::array<long, 2>> array_vec = {{100L, 101L}, {200L, 201L}, {300L, 301L}};
std::unordered_multimap umm3(array_vec.begin(), array_vec.end());
ASSERT_SAME_TYPE(decltype(umm3), std::unordered_multimap<long, long>);
std::vector<std::pair<int, char>> non_const_key_pair_vec = {{5, 'a'}, {6, 'b'}};
std::unordered_multimap umm4(non_const_key_pair_vec.begin(), non_const_key_pair_vec.end());
ASSERT_SAME_TYPE(decltype(umm4), std::unordered_multimap<int, char>);
}
#endif
UnorderedContainerDeductionGuidesSfinaeAway<std::unordered_multimap, std::unordered_multimap<int, long>>();

View File

@@ -56,7 +56,9 @@
// Allocator)
// -> unordered_multimap<Key, T, Hash, equal_to<Key>, Allocator>;
#include <array>
#include <functional>
#include <tuple>
#include <unordered_map>
int main(int, char**) {
@@ -101,6 +103,18 @@ int main(int, char**) {
std::unordered_multimap m(42, std::hash<int>(), std::allocator<P>());
// expected-error-re@-1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}unordered_multimap'}}
}
{
// cannot deduce from tuple-like objects without proper iterator
std::tuple<int, double> t{1, 2.0};
std::unordered_multimap m(t);
// expected-error-re@-1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}unordered_multimap'}}
}
{
// cannot deduce from array-like objects without proper iterator
std::array<int, 2> arr{1, 2};
std::unordered_multimap m(arr);
// expected-error-re@-1{{no viable constructor or deduction guide for deduction of template arguments of '{{(std::)?}}unordered_multimap'}}
}
return 0;
}