[libcxx-commits] [libcxx] r368599 - [libc++] Implement CTAD for std::tuple

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Mon Aug 12 11:30:32 PDT 2019


Author: ldionne
Date: Mon Aug 12 11:30:31 2019
New Revision: 368599

URL: http://llvm.org/viewvc/llvm-project?rev=368599&view=rev
Log:
[libc++] Implement CTAD for std::tuple

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

Added:
    libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/deduct.pass.cpp
Removed:
    libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/implicit_deduction_guides.pass.cpp
Modified:
    libcxx/trunk/include/tuple

Modified: libcxx/trunk/include/tuple
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/tuple?rev=368599&r1=368598&r2=368599&view=diff
==============================================================================
--- libcxx/trunk/include/tuple (original)
+++ libcxx/trunk/include/tuple Mon Aug 12 11:30:31 2019
@@ -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
@@ -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>

Added: libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/deduct.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/deduct.pass.cpp?rev=368599&view=auto
==============================================================================
--- libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/deduct.pass.cpp (added)
+++ libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/deduct.pass.cpp Mon Aug 12 11:30:31 2019
@@ -0,0 +1,201 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+// UNSUPPORTED: libcpp-no-deduction-guides
+
+// GCC's implementation of class template deduction is still immature and runs
+// into issues with libc++. However GCC accepts this code when compiling
+// against libstdc++.
+// XFAIL: gcc
+
+// <tuple>
+
+// Test that the constructors offered by std::tuple are formulated
+// so they're compatible with implicit deduction guides, or if that's not
+// possible that they provide explicit guides to make it work.
+
+#include <tuple>
+#include <memory>
+#include <cassert>
+
+#include "test_macros.h"
+#include "archetypes.hpp"
+
+
+// Overloads
+//  using A = Allocator
+//  using AT = std::allocator_arg_t
+// ---------------
+// (1)  tuple(const Types&...) -> tuple<Types...>
+// (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;
+  const auto AT = std::allocator_arg;
+  { // Testing (1)
+    int x = 101;
+    std::tuple t1(42);
+    ASSERT_SAME_TYPE(decltype(t1), std::tuple<int>);
+    std::tuple t2(x, 0.0, nullptr);
+    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, "");
+
+    std::tuple t1(T{});
+    ASSERT_SAME_TYPE(decltype(t1), std::tuple<T>);
+
+    const T v{};
+    std::tuple t2(T{}, 101l, v);
+    ASSERT_SAME_TYPE(decltype(t2), std::tuple<T, long, T>);
+  }
+  { // 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 (5)
+    using T = ExplicitTestTypes::TestType;
+    static_assert(!std::is_convertible<T const&, T>::value, "");
+
+    std::tuple t1(AT, A, T{});
+    ASSERT_SAME_TYPE(decltype(t1), std::tuple<T>);
+
+    const T v{};
+    std::tuple t2(AT, A, T{}, 101l, v);
+    ASSERT_SAME_TYPE(decltype(t2), std::tuple<T, long, T>);
+  }
+  { // 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 (8)
+    using Tup = std::tuple<void*, unsigned, char>;
+    std::tuple t1(Tup(nullptr, 42, 'a'));
+    ASSERT_SAME_TYPE(decltype(t1), Tup);
+  }
+  { // 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 (10)
+    using Tup = std::tuple<void*, unsigned, char>;
+    std::tuple t1(AT, A, Tup(nullptr, 42, 'a'));
+    ASSERT_SAME_TYPE(decltype(t1), Tup);
+  }
+}
+
+// Overloads
+//  using A = Allocator
+//  using AT = std::allocator_arg_t
+// ---------------
+// (1)  tuple() -> tuple<>
+// (2)  tuple(AT, A const&) -> tuple<>
+// (3)  tuple(tuple const&) -> tuple<>
+// (4)  tuple(tuple&&) -> tuple<>
+// (5)  tuple(AT, A const&, tuple const&) -> tuple<>
+// (6)  tuple(AT, A const&, tuple&&) -> tuple<>
+void test_empty_specialization()
+{
+  std::allocator<int> A;
+  const auto AT = std::allocator_arg;
+  { // Testing (1)
+    std::tuple t1{};
+    ASSERT_SAME_TYPE(decltype(t1), std::tuple<>);
+  }
+  { // Testing (2)
+    std::tuple t1{AT, A};
+    ASSERT_SAME_TYPE(decltype(t1), std::tuple<>);
+  }
+  { // Testing (3)
+    const std::tuple<> t{};
+    std::tuple t1(t);
+    ASSERT_SAME_TYPE(decltype(t1), std::tuple<>);
+  }
+  { // Testing (4)
+    std::tuple t1(std::tuple<>{});
+    ASSERT_SAME_TYPE(decltype(t1), std::tuple<>);
+  }
+  { // Testing (5)
+    const std::tuple<> t{};
+    std::tuple t1(AT, A, t);
+    ASSERT_SAME_TYPE(decltype(t1), std::tuple<>);
+  }
+  { // Testing (6)
+    std::tuple t1(AT, A, std::tuple<>{});
+    ASSERT_SAME_TYPE(decltype(t1), std::tuple<>);
+  }
+}
+
+int main(int, char**) {
+  test_primary_template();
+  test_empty_specialization();
+
+  return 0;
+}

Removed: libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/implicit_deduction_guides.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/implicit_deduction_guides.pass.cpp?rev=368598&view=auto
==============================================================================
--- libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/implicit_deduction_guides.pass.cpp (original)
+++ libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/implicit_deduction_guides.pass.cpp (removed)
@@ -1,157 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++98, c++03, c++11, c++14
-// UNSUPPORTED: libcpp-no-deduction-guides
-
-// GCC's implementation of class template deduction is still immature and runs
-// into issues with libc++. However GCC accepts this code when compiling
-// against libstdc++.
-// XFAIL: gcc
-
-// <tuple>
-
-// Test that the constructors offered by std::tuple are formulated
-// so they're compatible with implicit deduction guides, or if that's not
-// possible that they provide explicit guides to make it work.
-
-#include <tuple>
-#include <memory>
-#include <cassert>
-
-#include "test_macros.h"
-#include "archetypes.hpp"
-
-
-// Overloads
-//  using A = Allocator
-//  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)
-void test_primary_template()
-{
-  const std::allocator<int> A;
-  const auto AT = std::allocator_arg;
-  { // Testing (1)
-    int x = 101;
-    std::tuple t1(42);
-    ASSERT_SAME_TYPE(decltype(t1), std::tuple<int>);
-    std::tuple t2(x, 0.0, nullptr);
-    ASSERT_SAME_TYPE(decltype(t2), std::tuple<int, double, decltype(nullptr)>);
-  }
-  { // Testing (2)
-    using T = ExplicitTestTypes::TestType;
-    static_assert(!std::is_convertible<T const&, T>::value, "");
-
-    std::tuple t1(T{});
-    ASSERT_SAME_TYPE(decltype(t1), std::tuple<T>);
-
-    const T v{};
-    std::tuple t2(T{}, 101l, v);
-    ASSERT_SAME_TYPE(decltype(t2), std::tuple<T, long, T>);
-  }
-  { // Testing (3)
-    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)
-    using T = ExplicitTestTypes::TestType;
-    static_assert(!std::is_convertible<T const&, T>::value, "");
-
-    std::tuple t1(AT, A, T{});
-    ASSERT_SAME_TYPE(decltype(t1), std::tuple<T>);
-
-    const T v{};
-    std::tuple t2(AT, A, T{}, 101l, v);
-    ASSERT_SAME_TYPE(decltype(t2), std::tuple<T, long, T>);
-  }
-  { // Testing (5)
-    using Tup = std::tuple<int, decltype(nullptr)>;
-    const Tup t(42, nullptr);
-
-    std::tuple t1(t);
-    ASSERT_SAME_TYPE(decltype(t1), Tup);
-  }
-  { // Testing (6)
-    using Tup = std::tuple<void*, unsigned, char>;
-    std::tuple t1(Tup(nullptr, 42, 'a'));
-    ASSERT_SAME_TYPE(decltype(t1), Tup);
-  }
-  { // Testing (7)
-    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)
-    using Tup = std::tuple<void*, unsigned, char>;
-    std::tuple t1(AT, A, Tup(nullptr, 42, 'a'));
-    ASSERT_SAME_TYPE(decltype(t1), Tup);
-  }
-}
-
-// Overloads
-//  using A = Allocator
-//  using AT = std::allocator_arg_t
-// ---------------
-// (1)  tuple() -> tuple<>
-// (2)  tuple(AT, A const&) -> tuple<>
-// (3)  tuple(tuple const&) -> tuple<>
-// (4)  tuple(tuple&&) -> tuple<>
-// (5)  tuple(AT, A const&, tuple const&) -> tuple<>
-// (6)  tuple(AT, A const&, tuple&&) -> tuple<>
-void test_empty_specialization()
-{
-  std::allocator<int> A;
-  const auto AT = std::allocator_arg;
-  { // Testing (1)
-    std::tuple t1{};
-    ASSERT_SAME_TYPE(decltype(t1), std::tuple<>);
-  }
-  { // Testing (2)
-    std::tuple t1{AT, A};
-    ASSERT_SAME_TYPE(decltype(t1), std::tuple<>);
-  }
-  { // Testing (3)
-    const std::tuple<> t{};
-    std::tuple t1(t);
-    ASSERT_SAME_TYPE(decltype(t1), std::tuple<>);
-  }
-  { // Testing (4)
-    std::tuple t1(std::tuple<>{});
-    ASSERT_SAME_TYPE(decltype(t1), std::tuple<>);
-  }
-  { // Testing (5)
-    const std::tuple<> t{};
-    std::tuple t1(AT, A, t);
-    ASSERT_SAME_TYPE(decltype(t1), std::tuple<>);
-  }
-  { // Testing (6)
-    std::tuple t1(AT, A, std::tuple<>{});
-    ASSERT_SAME_TYPE(decltype(t1), std::tuple<>);
-  }
-}
-
-int main(int, char**) {
-  test_primary_template();
-  test_empty_specialization();
-
-  return 0;
-}




More information about the libcxx-commits mailing list