Skip to content

Commit

Permalink
[libc++] Implement CTAD for std::tuple
Browse files Browse the repository at this point in the history
Summary:
We were using implicit deduction guides instead of explicit ones,
however the implicit ones don't do work anymore when changing the
constructors.

This commit adds the actual guides specified in the Standard to make
libc++ (1) closer to the Standard and (2) more resistent to changes
in std::tuple's constructors.

Reviewers: Quuxplusone

Subscribers: christof, jkorous, dexonsmith, libcxx-commits

Tags: #libc

Differential Revision: https://reviews.llvm.org/D65225

llvm-svn: 368599
  • Loading branch information
ldionne committed Aug 12, 2019
1 parent 38a1aa1 commit 1308011
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 20 deletions.
28 changes: 21 additions & 7 deletions libcxx/include/tuple
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,17 @@ public:
void swap(tuple&) noexcept(AND(swap(declval<T&>(), declval<T&>())...));
};
template <class ...T>
tuple(T...) -> tuple<T...>; // since C++17
template <class T1, class T2>
tuple(pair<T1, T2>) -> tuple<T1, T2>; // since C++17
template <class Alloc, class ...T>
tuple(allocator_arg_t, Alloc, T...) -> tuple<T...>; // since C++17
template <class Alloc, class T1, class T2>
tuple(allocator_arg_t, Alloc, pair<T1, T2>) -> tuple<T1, T2>; // since C++17
template <class Alloc, class ...T>
tuple(allocator_arg_t, Alloc, tuple<T...>) -> tuple<T...>; // since C++17
inline constexpr unspecified ignore;
template <class... T> tuple<V...> make_tuple(T&&...); // constexpr in C++14
Expand Down Expand Up @@ -943,13 +954,16 @@ public:
};

#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 <class _Alloc, class ..._Args>
tuple(allocator_arg_t, const _Alloc&, tuple<_Args...> const&) -> tuple<_Args...>;
template <class _Alloc, class ..._Args>
tuple(allocator_arg_t, const _Alloc&, tuple<_Args...>&&) -> tuple<_Args...>;
template <class ..._Tp>
tuple(_Tp...) -> tuple<_Tp...>;
template <class _Tp1, class _Tp2>
tuple(pair<_Tp1, _Tp2>) -> tuple<_Tp1, _Tp2>;
template <class _Alloc, class ..._Tp>
tuple(allocator_arg_t, _Alloc, _Tp...) -> tuple<_Tp...>;
template <class _Alloc, class _Tp1, class _Tp2>
tuple(allocator_arg_t, _Alloc, pair<_Tp1, _Tp2>) -> tuple<_Tp1, _Tp2>;
template <class _Alloc, class ..._Tp>
tuple(allocator_arg_t, _Alloc, tuple<_Tp...>) -> tuple<_Tp...>;
#endif

template <class ..._Tp>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,15 @@
// using AT = std::allocator_arg_t
// ---------------
// (1) tuple(const Types&...) -> tuple<Types...>
// (2) explicit tuple(const Types&...) -> tuple<Types...>
// (3) tuple(AT, A const&, Types const&...) -> tuple<Types...>
// (4) explicit tuple(AT, A const&, Types const&...) -> tuple<Types...>
// (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<T1, T2>) -> tuple<T1, T2>;
// (3) explicit tuple(const Types&...) -> tuple<Types...>
// (4) tuple(AT, A const&, Types const&...) -> tuple<Types...>
// (5) explicit tuple(AT, A const&, Types const&...) -> tuple<Types...>
// (6) tuple(AT, A, pair<T1, T2>) -> tuple<T1, T2>
// (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<int> A;
Expand All @@ -52,6 +54,27 @@ void test_primary_template()
ASSERT_SAME_TYPE(decltype(t2), std::tuple<int, double, decltype(nullptr)>);
}
{ // Testing (2)
std::pair<int, char> p1(1, 'c');
std::tuple t1(p1);
ASSERT_SAME_TYPE(decltype(t1), std::tuple<int, char>);

std::pair<int, std::tuple<char, long, void*>> p2(1, std::tuple<char, long, void*>('c', 3l, nullptr));
std::tuple t2(p2);
ASSERT_SAME_TYPE(decltype(t2), std::tuple<int, std::tuple<char, long, void*>>);

int i = 3;
std::pair<std::reference_wrapper<int>, char> p3(std::ref(i), 'c');
std::tuple t3(p3);
ASSERT_SAME_TYPE(decltype(t3), std::tuple<std::reference_wrapper<int>, char>);

std::pair<int&, char> p4(i, 'c');
std::tuple t4(p4);
ASSERT_SAME_TYPE(decltype(t4), std::tuple<int&, char>);

std::tuple t5(std::pair<int, char>(1, 'c'));
ASSERT_SAME_TYPE(decltype(t5), std::tuple<int, char>);
}
{ // Testing (3)
using T = ExplicitTestTypes::TestType;
static_assert(!std::is_convertible<T const&, T>::value, "");

Expand All @@ -62,15 +85,15 @@ void test_primary_template()
std::tuple t2(T{}, 101l, v);
ASSERT_SAME_TYPE(decltype(t2), std::tuple<T, long, T>);
}
{ // Testing (3)
{ // Testing (4)
int x = 101;
std::tuple t1(AT, A, 42);
ASSERT_SAME_TYPE(decltype(t1), std::tuple<int>);

std::tuple t2(AT, A, 42, 0.0, x);
ASSERT_SAME_TYPE(decltype(t2), std::tuple<int, double, int>);
}
{ // Testing (4)
{ // Testing (5)
using T = ExplicitTestTypes::TestType;
static_assert(!std::is_convertible<T const&, T>::value, "");

Expand All @@ -81,26 +104,47 @@ void test_primary_template()
std::tuple t2(AT, A, T{}, 101l, v);
ASSERT_SAME_TYPE(decltype(t2), std::tuple<T, long, T>);
}
{ // Testing (5)
{ // Testing (6)
std::pair<int, char> p1(1, 'c');
std::tuple t1(AT, A, p1);
ASSERT_SAME_TYPE(decltype(t1), std::tuple<int, char>);

std::pair<int, std::tuple<char, long, void*>> p2(1, std::tuple<char, long, void*>('c', 3l, nullptr));
std::tuple t2(AT, A, p2);
ASSERT_SAME_TYPE(decltype(t2), std::tuple<int, std::tuple<char, long, void*>>);

int i = 3;
std::pair<std::reference_wrapper<int>, char> p3(std::ref(i), 'c');
std::tuple t3(AT, A, p3);
ASSERT_SAME_TYPE(decltype(t3), std::tuple<std::reference_wrapper<int>, char>);

std::pair<int&, char> p4(i, 'c');
std::tuple t4(AT, A, p4);
ASSERT_SAME_TYPE(decltype(t4), std::tuple<int&, char>);

std::tuple t5(AT, A, std::pair<int, char>(1, 'c'));
ASSERT_SAME_TYPE(decltype(t5), std::tuple<int, char>);
}
{ // Testing (7)
using Tup = std::tuple<int, decltype(nullptr)>;
const Tup t(42, nullptr);

std::tuple t1(t);
ASSERT_SAME_TYPE(decltype(t1), Tup);
}
{ // Testing (6)
{ // Testing (8)
using Tup = std::tuple<void*, unsigned, char>;
std::tuple t1(Tup(nullptr, 42, 'a'));
ASSERT_SAME_TYPE(decltype(t1), Tup);
}
{ // Testing (7)
{ // Testing (9)
using Tup = std::tuple<int, decltype(nullptr)>;
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<void*, unsigned, char>;
std::tuple t1(AT, A, Tup(nullptr, 42, 'a'));
ASSERT_SAME_TYPE(decltype(t1), Tup);
Expand Down

0 comments on commit 1308011

Please sign in to comment.