1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 // UNSUPPORTED: c++03, c++11, c++14 10 11 // <tuple> 12 13 // template <class T, class Tuple> constexpr T make_from_tuple(Tuple&&); 14 15 #include <tuple> 16 #include <array> 17 #include <utility> 18 #include <string> 19 #include <cassert> 20 21 #include "test_macros.h" 22 #include "type_id.h" 23 24 template <class Tuple> 25 struct ConstexprConstructibleFromTuple { 26 template <class ...Args> 27 explicit constexpr ConstexprConstructibleFromTuple(Args&&... xargs) 28 : args{std::forward<Args>(xargs)...} {} 29 Tuple args; 30 }; 31 32 template <class TupleLike> 33 struct ConstructibleFromTuple; 34 35 template <template <class ...> class Tuple, class ...Types> 36 struct ConstructibleFromTuple<Tuple<Types...>> { 37 template <class ...Args> 38 explicit ConstructibleFromTuple(Args&&... xargs) 39 : args(xargs...), 40 arg_types(&makeArgumentID<Args&&...>()) 41 {} 42 Tuple<std::decay_t<Types>...> args; 43 TypeID const* arg_types; 44 }; 45 46 template <class Tp, size_t N> 47 struct ConstructibleFromTuple<std::array<Tp, N>> { 48 template <class ...Args> 49 explicit ConstructibleFromTuple(Args&&... xargs) 50 : args{xargs...}, 51 arg_types(&makeArgumentID<Args&&...>()) 52 {} 53 std::array<Tp, N> args; 54 TypeID const* arg_types; 55 }; 56 57 template <class Tuple> 58 constexpr bool do_constexpr_test(Tuple&& tup) { 59 using RawTuple = std::decay_t<Tuple>; 60 using Tp = ConstexprConstructibleFromTuple<RawTuple>; 61 return std::make_from_tuple<Tp>(std::forward<Tuple>(tup)).args == tup; 62 } 63 64 // Needed by do_forwarding_test() since it compares pairs of different types. 65 template <class T1, class T2, class U1, class U2> 66 inline bool operator==(const std::pair<T1, T2>& lhs, const std::pair<U1, U2>& rhs) { 67 return lhs.first == rhs.first && lhs.second == rhs.second; 68 } 69 70 template <class ...ExpectTypes, class Tuple> 71 bool do_forwarding_test(Tuple&& tup) { 72 using RawTuple = std::decay_t<Tuple>; 73 using Tp = ConstructibleFromTuple<RawTuple>; 74 const Tp value = std::make_from_tuple<Tp>(std::forward<Tuple>(tup)); 75 return value.args == tup 76 && value.arg_types == &makeArgumentID<ExpectTypes...>(); 77 } 78 79 void test_constexpr_construction() { 80 { 81 constexpr std::tuple<> tup; 82 static_assert(do_constexpr_test(tup), ""); 83 } 84 { 85 constexpr std::tuple<int> tup(42); 86 static_assert(do_constexpr_test(tup), ""); 87 } 88 { 89 constexpr std::tuple<int, long, void*> tup(42, 101, nullptr); 90 static_assert(do_constexpr_test(tup), ""); 91 } 92 { 93 constexpr std::pair<int, const char*> p(42, "hello world"); 94 static_assert(do_constexpr_test(p), ""); 95 } 96 { 97 using Tuple = std::array<int, 3>; 98 using ValueTp = ConstexprConstructibleFromTuple<Tuple>; 99 constexpr Tuple arr = {42, 101, -1}; 100 constexpr ValueTp value = std::make_from_tuple<ValueTp>(arr); 101 static_assert(value.args[0] == arr[0] && value.args[1] == arr[1] 102 && value.args[2] == arr[2], ""); 103 } 104 } 105 106 void test_perfect_forwarding() { 107 { 108 using Tup = std::tuple<>; 109 Tup tup; 110 Tup const& ctup = tup; 111 assert(do_forwarding_test<>(tup)); 112 assert(do_forwarding_test<>(ctup)); 113 } 114 { 115 using Tup = std::tuple<int>; 116 Tup tup(42); 117 Tup const& ctup = tup; 118 assert(do_forwarding_test<int&>(tup)); 119 assert(do_forwarding_test<int const&>(ctup)); 120 assert(do_forwarding_test<int&&>(std::move(tup))); 121 assert(do_forwarding_test<int const&&>(std::move(ctup))); 122 } 123 { 124 using Tup = std::tuple<int&, const char*, unsigned&&>; 125 int x = 42; 126 unsigned y = 101; 127 Tup tup(x, "hello world", std::move(y)); 128 Tup const& ctup = tup; 129 assert((do_forwarding_test<int&, const char*&, unsigned&>(tup))); 130 assert((do_forwarding_test<int&, const char* const&, unsigned &>(ctup))); 131 assert((do_forwarding_test<int&, const char*&&, unsigned&&>(std::move(tup)))); 132 assert((do_forwarding_test<int&, const char* const&&, unsigned &&>(std::move(ctup)))); 133 } 134 // test with pair<T, U> 135 { 136 using Tup = std::pair<int&, const char*>; 137 int x = 42; 138 Tup tup(x, "hello world"); 139 Tup const& ctup = tup; 140 assert((do_forwarding_test<int&, const char*&>(tup))); 141 assert((do_forwarding_test<int&, const char* const&>(ctup))); 142 assert((do_forwarding_test<int&, const char*&&>(std::move(tup)))); 143 assert((do_forwarding_test<int&, const char* const&&>(std::move(ctup)))); 144 } 145 // test with array<T, I> 146 { 147 using Tup = std::array<int, 3>; 148 Tup tup = {42, 101, -1}; 149 Tup const& ctup = tup; 150 assert((do_forwarding_test<int&, int&, int&>(tup))); 151 assert((do_forwarding_test<int const&, int const&, int const&>(ctup))); 152 assert((do_forwarding_test<int&&, int&&, int&&>(std::move(tup)))); 153 assert((do_forwarding_test<int const&&, int const&&, int const&&>(std::move(ctup)))); 154 } 155 } 156 157 void test_noexcept() { 158 struct NothrowMoveable { 159 NothrowMoveable() = default; 160 NothrowMoveable(NothrowMoveable const&) {} 161 NothrowMoveable(NothrowMoveable&&) noexcept {} 162 }; 163 struct TestType { 164 TestType(int, NothrowMoveable) noexcept {} 165 TestType(int, int, int) noexcept(false) {} 166 TestType(long, long, long) noexcept {} 167 }; 168 { 169 using Tuple = std::tuple<int, NothrowMoveable>; 170 Tuple tup; ((void)tup); 171 Tuple const& ctup = tup; ((void)ctup); 172 ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(ctup)); 173 LIBCPP_ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(std::move(tup))); 174 } 175 { 176 using Tuple = std::pair<int, NothrowMoveable>; 177 Tuple tup; ((void)tup); 178 Tuple const& ctup = tup; ((void)ctup); 179 ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(ctup)); 180 LIBCPP_ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(std::move(tup))); 181 } 182 { 183 using Tuple = std::tuple<int, int, int>; 184 Tuple tup; ((void)tup); 185 ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(tup)); 186 } 187 { 188 using Tuple = std::tuple<long, long, long>; 189 Tuple tup; ((void)tup); 190 LIBCPP_ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(tup)); 191 } 192 { 193 using Tuple = std::array<int, 3>; 194 Tuple tup; ((void)tup); 195 ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(tup)); 196 } 197 { 198 using Tuple = std::array<long, 3>; 199 Tuple tup; ((void)tup); 200 LIBCPP_ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(tup)); 201 } 202 } 203 204 int main(int, char**) 205 { 206 test_constexpr_construction(); 207 test_perfect_forwarding(); 208 test_noexcept(); 209 210 return 0; 211 } 212