[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:
@@ -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;
|
||||
|
||||
@@ -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>>();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>>();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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'}}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>>();
|
||||
|
||||
|
||||
@@ -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'}}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>>();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>>();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user