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