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