diff --git a/libcxx/include/tuple b/libcxx/include/tuple --- a/libcxx/include/tuple +++ b/libcxx/include/tuple @@ -69,6 +69,17 @@ void swap(tuple&) noexcept(AND(swap(declval(), declval())...)); }; +template +tuple(T...) -> tuple; // since C++17 +template +tuple(pair) -> tuple; // since C++17 +template +tuple(allocator_arg_t, Alloc, T...) -> tuple; // since C++17 +template +tuple(allocator_arg_t, Alloc, pair) -> tuple; // since C++17 +template +tuple(allocator_arg_t, Alloc, tuple) -> tuple; // since C++17 + inline constexpr unspecified ignore; template tuple make_tuple(T&&...); // constexpr in C++14 @@ -943,13 +954,16 @@ }; #ifndef _LIBCPP_HAS_NO_DEDUCTION_GUIDES -// NOTE: These are not yet standardized, but are required to simulate the -// implicit deduction guide that should be generated had libc++ declared the -// tuple-like constructors "correctly" -template -tuple(allocator_arg_t, const _Alloc&, tuple<_Args...> const&) -> tuple<_Args...>; -template -tuple(allocator_arg_t, const _Alloc&, tuple<_Args...>&&) -> tuple<_Args...>; +template +tuple(_Tp...) -> tuple<_Tp...>; +template +tuple(pair<_Tp1, _Tp2>) -> tuple<_Tp1, _Tp2>; +template +tuple(allocator_arg_t, _Alloc, _Tp...) -> tuple<_Tp...>; +template +tuple(allocator_arg_t, _Alloc, pair<_Tp1, _Tp2>) -> tuple<_Tp1, _Tp2>; +template +tuple(allocator_arg_t, _Alloc, tuple<_Tp...>) -> tuple<_Tp...>; #endif template diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/implicit_deduction_guides.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/deduct.pass.cpp rename from libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/implicit_deduction_guides.pass.cpp rename to libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/deduct.pass.cpp --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/implicit_deduction_guides.pass.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/deduct.pass.cpp @@ -33,13 +33,15 @@ // using AT = std::allocator_arg_t // --------------- // (1) tuple(const Types&...) -> tuple -// (2) explicit tuple(const Types&...) -> tuple -// (3) tuple(AT, A const&, Types const&...) -> tuple -// (4) explicit tuple(AT, A const&, Types const&...) -> tuple -// (5) tuple(tuple const& t) -> decltype(t) -// (6) tuple(tuple&& t) -> decltype(t) -// (7) tuple(AT, A const&, tuple const& t) -> decltype(t) -// (8) tuple(AT, A const&, tuple&& t) -> decltype(t) +// (2) tuple(pair) -> tuple; +// (3) explicit tuple(const Types&...) -> tuple +// (4) tuple(AT, A const&, Types const&...) -> tuple +// (5) explicit tuple(AT, A const&, Types const&...) -> tuple +// (6) tuple(AT, A, pair) -> tuple +// (7) tuple(tuple const& t) -> decltype(t) +// (8) tuple(tuple&& t) -> decltype(t) +// (9) tuple(AT, A const&, tuple const& t) -> decltype(t) +// (10) tuple(AT, A const&, tuple&& t) -> decltype(t) void test_primary_template() { const std::allocator A; @@ -52,6 +54,24 @@ ASSERT_SAME_TYPE(decltype(t2), std::tuple); } { // Testing (2) + std::pair p1(1, 'c'); + std::tuple t1(p1); + ASSERT_SAME_TYPE(decltype(t1), std::tuple); + + std::pair> p2(1, std::tuple('c', 3l, nullptr)); + std::tuple t2(p2); + ASSERT_SAME_TYPE(decltype(t2), std::tuple>); + + int i = 3; + std::pair, char> p3(std::ref(i), 'c'); + std::tuple t3(p3); + ASSERT_SAME_TYPE(decltype(t3), std::tuple, char>); + + std::pair p4(i, 'c'); + std::tuple t4(p4); + ASSERT_SAME_TYPE(decltype(t4), std::tuple); + } + { // Testing (3) using T = ExplicitTestTypes::TestType; static_assert(!std::is_convertible::value, ""); @@ -62,7 +82,7 @@ std::tuple t2(T{}, 101l, v); ASSERT_SAME_TYPE(decltype(t2), std::tuple); } - { // Testing (3) + { // Testing (4) int x = 101; std::tuple t1(AT, A, 42); ASSERT_SAME_TYPE(decltype(t1), std::tuple); @@ -70,7 +90,7 @@ std::tuple t2(AT, A, 42, 0.0, x); ASSERT_SAME_TYPE(decltype(t2), std::tuple); } - { // Testing (4) + { // Testing (5) using T = ExplicitTestTypes::TestType; static_assert(!std::is_convertible::value, ""); @@ -81,26 +101,44 @@ std::tuple t2(AT, A, T{}, 101l, v); ASSERT_SAME_TYPE(decltype(t2), std::tuple); } - { // Testing (5) + { // Testing (6) + std::pair p1(1, 'c'); + std::tuple t1(AT, A, p1); + ASSERT_SAME_TYPE(decltype(t1), std::tuple); + + std::pair> p2(1, std::tuple('c', 3l, nullptr)); + std::tuple t2(AT, A, p2); + ASSERT_SAME_TYPE(decltype(t2), std::tuple>); + + int i = 3; + std::pair, char> p3(std::ref(i), 'c'); + std::tuple t3(AT, A, p3); + ASSERT_SAME_TYPE(decltype(t3), std::tuple, char>); + + std::pair p4(i, 'c'); + std::tuple t4(AT, A, p4); + ASSERT_SAME_TYPE(decltype(t4), std::tuple); + } + { // Testing (7) using Tup = std::tuple; const Tup t(42, nullptr); std::tuple t1(t); ASSERT_SAME_TYPE(decltype(t1), Tup); } - { // Testing (6) + { // Testing (8) using Tup = std::tuple; std::tuple t1(Tup(nullptr, 42, 'a')); ASSERT_SAME_TYPE(decltype(t1), Tup); } - { // Testing (7) + { // Testing (9) using Tup = std::tuple; const Tup t(42, nullptr); std::tuple t1(AT, A, t); ASSERT_SAME_TYPE(decltype(t1), Tup); } - { // Testing (8) + { // Testing (10) using Tup = std::tuple; std::tuple t1(AT, A, Tup(nullptr, 42, 'a')); ASSERT_SAME_TYPE(decltype(t1), Tup);