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