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, std::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 template <class ...ExpectTypes, class Tuple> 65 bool do_forwarding_test(Tuple&& tup) { 66 using RawTuple = std::decay_t<Tuple>; 67 using Tp = ConstructibleFromTuple<RawTuple>; 68 const Tp value = std::make_from_tuple<Tp>(std::forward<Tuple>(tup)); 69 return value.args == tup 70 && value.arg_types == &makeArgumentID<ExpectTypes...>(); 71 } 72 73 void test_constexpr_construction() { 74 { 75 constexpr std::tuple<> tup; 76 static_assert(do_constexpr_test(tup), ""); 77 } 78 { 79 constexpr std::tuple<int> tup(42); 80 static_assert(do_constexpr_test(tup), ""); 81 } 82 { 83 constexpr std::tuple<int, long, void*> tup(42, 101, nullptr); 84 static_assert(do_constexpr_test(tup), ""); 85 } 86 { 87 constexpr std::pair<int, const char*> p(42, "hello world"); 88 static_assert(do_constexpr_test(p), ""); 89 } 90 { 91 using Tuple = std::array<int, 3>; 92 using ValueTp = ConstexprConstructibleFromTuple<Tuple>; 93 constexpr Tuple arr = {42, 101, -1}; 94 constexpr ValueTp value = std::make_from_tuple<ValueTp>(arr); 95 static_assert(value.args[0] == arr[0] && value.args[1] == arr[1] 96 && value.args[2] == arr[2], ""); 97 } 98 } 99 100 void test_perfect_forwarding() { 101 { 102 using Tup = std::tuple<>; 103 Tup tup; 104 Tup const& ctup = tup; 105 assert(do_forwarding_test<>(tup)); 106 assert(do_forwarding_test<>(ctup)); 107 } 108 { 109 using Tup = std::tuple<int>; 110 Tup tup(42); 111 Tup const& ctup = tup; 112 assert(do_forwarding_test<int&>(tup)); 113 assert(do_forwarding_test<int const&>(ctup)); 114 assert(do_forwarding_test<int&&>(std::move(tup))); 115 assert(do_forwarding_test<int const&&>(std::move(ctup))); 116 } 117 { 118 using Tup = std::tuple<int&, const char*, unsigned&&>; 119 int x = 42; 120 unsigned y = 101; 121 Tup tup(x, "hello world", std::move(y)); 122 Tup const& ctup = tup; 123 assert((do_forwarding_test<int&, const char*&, unsigned&>(tup))); 124 assert((do_forwarding_test<int&, const char* const&, unsigned &>(ctup))); 125 assert((do_forwarding_test<int&, const char*&&, unsigned&&>(std::move(tup)))); 126 assert((do_forwarding_test<int&, const char* const&&, unsigned &&>(std::move(ctup)))); 127 } 128 // test with pair<T, U> 129 { 130 using Tup = std::pair<int&, const char*>; 131 int x = 42; 132 Tup tup(x, "hello world"); 133 Tup const& ctup = tup; 134 assert((do_forwarding_test<int&, const char*&>(tup))); 135 assert((do_forwarding_test<int&, const char* const&>(ctup))); 136 assert((do_forwarding_test<int&, const char*&&>(std::move(tup)))); 137 assert((do_forwarding_test<int&, const char* const&&>(std::move(ctup)))); 138 } 139 // test with array<T, I> 140 { 141 using Tup = std::array<int, 3>; 142 Tup tup = {42, 101, -1}; 143 Tup const& ctup = tup; 144 assert((do_forwarding_test<int&, int&, int&>(tup))); 145 assert((do_forwarding_test<int const&, int const&, int const&>(ctup))); 146 assert((do_forwarding_test<int&&, int&&, int&&>(std::move(tup)))); 147 assert((do_forwarding_test<int const&&, int const&&, int const&&>(std::move(ctup)))); 148 } 149 } 150 151 void test_noexcept() { 152 struct NothrowMoveable { 153 NothrowMoveable() = default; 154 NothrowMoveable(NothrowMoveable const&) {} 155 NothrowMoveable(NothrowMoveable&&) noexcept {} 156 }; 157 struct TestType { 158 TestType(int, NothrowMoveable) noexcept {} 159 TestType(int, int, int) noexcept(false) {} 160 TestType(long, long, long) noexcept {} 161 }; 162 { 163 using Tuple = std::tuple<int, NothrowMoveable>; 164 Tuple tup; ((void)tup); 165 Tuple const& ctup = tup; ((void)ctup); 166 ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(ctup)); 167 LIBCPP_ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(std::move(tup))); 168 } 169 { 170 using Tuple = std::pair<int, NothrowMoveable>; 171 Tuple tup; ((void)tup); 172 Tuple const& ctup = tup; ((void)ctup); 173 ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(ctup)); 174 LIBCPP_ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(std::move(tup))); 175 } 176 { 177 using Tuple = std::tuple<int, int, int>; 178 Tuple tup; ((void)tup); 179 ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(tup)); 180 } 181 { 182 using Tuple = std::tuple<long, long, long>; 183 Tuple tup; ((void)tup); 184 LIBCPP_ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(tup)); 185 } 186 { 187 using Tuple = std::array<int, 3>; 188 Tuple tup; ((void)tup); 189 ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(tup)); 190 } 191 { 192 using Tuple = std::array<long, 3>; 193 Tuple tup; ((void)tup); 194 LIBCPP_ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(tup)); 195 } 196 } 197 198 namespace LWG3528 { 199 template <class T, class Tuple> 200 auto test_make_from_tuple(T&&, Tuple&& t) -> decltype(std::make_from_tuple<T>(t), uint8_t()) { 201 return 0; 202 } 203 template <class T, class Tuple> 204 uint32_t test_make_from_tuple(...) { 205 return 0; 206 } 207 208 template <class T, class Tuple> 209 static constexpr bool can_make_from_tuple = 210 std::is_same_v<decltype(test_make_from_tuple<T, Tuple>(T{}, Tuple{})), uint8_t>; 211 212 template <class T, class Tuple> 213 auto test_make_from_tuple_impl(T&&, Tuple&& t) 214 -> decltype(std::__make_from_tuple_impl<T>( 215 t, typename std::__make_tuple_indices< std::tuple_size_v<std::remove_reference_t<Tuple>>>::type{}), 216 uint8_t()) { 217 return 0; 218 } 219 template <class T, class Tuple> 220 uint32_t test_make_from_tuple_impl(...) { 221 return 0; 222 } 223 224 template <class T, class Tuple> 225 static constexpr bool can_make_from_tuple_impl = 226 std::is_same_v<decltype(test_make_from_tuple_impl<T, Tuple>(T{}, Tuple{})), uint8_t>; 227 228 struct A { 229 int a; 230 }; 231 struct B : public A {}; 232 233 struct C { 234 C(const B&) {} 235 }; 236 237 enum class D { 238 ONE, 239 TWO, 240 }; 241 242 // Test std::make_from_tuple constraints. 243 244 // reinterpret_cast 245 static_assert(!can_make_from_tuple<int*, std::tuple<A*>>); 246 static_assert(can_make_from_tuple<A*, std::tuple<A*>>); 247 248 // const_cast 249 static_assert(!can_make_from_tuple<char*, std::tuple<const char*>>); 250 static_assert(!can_make_from_tuple<volatile char*, std::tuple<const volatile char*>>); 251 static_assert(can_make_from_tuple<volatile char*, std::tuple<volatile char*>>); 252 static_assert(can_make_from_tuple<char*, std::tuple<char*>>); 253 static_assert(can_make_from_tuple<const char*, std::tuple<char*>>); 254 static_assert(can_make_from_tuple<const volatile char*, std::tuple<volatile char*>>); 255 256 // static_cast 257 static_assert(!can_make_from_tuple<int, std::tuple<D>>); 258 static_assert(!can_make_from_tuple<D, std::tuple<int>>); 259 static_assert(can_make_from_tuple<long, std::tuple<int>>); 260 static_assert(can_make_from_tuple<double, std::tuple<float>>); 261 static_assert(can_make_from_tuple<float, std::tuple<double>>); 262 263 // Test std::__make_from_tuple_impl constraints. 264 265 // reinterpret_cast 266 static_assert(!can_make_from_tuple_impl<int*, std::tuple<A*>>); 267 static_assert(can_make_from_tuple_impl<A*, std::tuple<A*>>); 268 269 // const_cast 270 static_assert(!can_make_from_tuple_impl<char*, std::tuple<const char*>>); 271 static_assert(!can_make_from_tuple_impl<volatile char*, std::tuple<const volatile char*>>); 272 static_assert(can_make_from_tuple_impl<volatile char*, std::tuple<volatile char*>>); 273 static_assert(can_make_from_tuple_impl<char*, std::tuple<char*>>); 274 static_assert(can_make_from_tuple_impl<const char*, std::tuple<char*>>); 275 static_assert(can_make_from_tuple_impl<const volatile char*, std::tuple<volatile char*>>); 276 277 // static_cast 278 static_assert(!can_make_from_tuple_impl<int, std::tuple<D>>); 279 static_assert(!can_make_from_tuple_impl<D, std::tuple<int>>); 280 static_assert(can_make_from_tuple_impl<long, std::tuple<int>>); 281 static_assert(can_make_from_tuple_impl<double, std::tuple<float>>); 282 static_assert(can_make_from_tuple_impl<float, std::tuple<double>>); 283 284 } // namespace LWG3528 285 286 int main(int, char**) 287 { 288 test_constexpr_construction(); 289 test_perfect_forwarding(); 290 test_noexcept(); 291 292 return 0; 293 } 294