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
25template <class Tuple>
26struct ConstexprConstructibleFromTuple {
27 template <class ...Args>
28 explicit constexpr ConstexprConstructibleFromTuple(Args&&... xargs)
29 : args{std::forward<Args>(xargs)...} {}
30 Tuple args;
31};
32
33template <class TupleLike>
34struct ConstructibleFromTuple;
35
36template <template <class ...> class Tuple, class ...Types>
37struct 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
47template <class Tp, std::size_t N>
48struct ConstructibleFromTuple<std::array<Tp, N>> {
49template <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
58template <class Tuple>
59constexpr 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
65template <class ...ExpectTypes, class Tuple>
66bool 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
74void 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(tup: 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>(t: arr);
96 static_assert(value.args[0] == arr[0] && value.args[1] == arr[1]
97 && value.args[2] == arr[2], "");
98 }
99}
100
101void 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
152void 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>(t: ctup));
168 LIBCPP_ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(t: 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>(t: ctup));
175 LIBCPP_ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(t: 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>(t&: 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>(t&: tup));
186 }
187 {
188 using Tuple = std::array<int, 3>;
189 Tuple tup; ((void)tup);
190 ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(t&: tup));
191 }
192 {
193 using Tuple = std::array<long, 3>;
194 Tuple tup; ((void)tup);
195 LIBCPP_ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(t&: tup));
196 }
197}
198
199namespace LWG3528 {
200template <class T, class Tuple>
201auto test_make_from_tuple(T&&, Tuple&& t) -> decltype(std::make_from_tuple<T>(t), std::uint8_t()) {
202 return 0;
203}
204template <class T, class Tuple>
205uint32_t test_make_from_tuple(...) {
206 return 0;
207}
208
209template <class T, class Tuple>
210static 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
214template <class T, class Tuple>
215auto 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}
221template <class T, class Tuple>
222uint32_t test_make_from_tuple_impl(...) {
223 return 0;
224}
225
226template <class T, class Tuple>
227static 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
231struct A {
232 int a;
233};
234struct B : public A {};
235
236struct C {
237 C(const B&) {}
238};
239
240enum class D {
241 ONE,
242 TWO,
243};
244
245// Test std::make_from_tuple constraints.
246
247// reinterpret_cast
248static_assert(!can_make_from_tuple<int*, std::tuple<A*>>);
249static_assert(can_make_from_tuple<A*, std::tuple<A*>>);
250
251// const_cast
252static_assert(!can_make_from_tuple<char*, std::tuple<const char*>>);
253static_assert(!can_make_from_tuple<volatile char*, std::tuple<const volatile char*>>);
254static_assert(can_make_from_tuple<volatile char*, std::tuple<volatile char*>>);
255static_assert(can_make_from_tuple<char*, std::tuple<char*>>);
256static_assert(can_make_from_tuple<const char*, std::tuple<char*>>);
257static_assert(can_make_from_tuple<const volatile char*, std::tuple<volatile char*>>);
258
259// static_cast
260static_assert(!can_make_from_tuple<int, std::tuple<D>>);
261static_assert(!can_make_from_tuple<D, std::tuple<int>>);
262static_assert(can_make_from_tuple<long, std::tuple<int>>);
263static_assert(can_make_from_tuple<double, std::tuple<float>>);
264static_assert(can_make_from_tuple<float, std::tuple<double>>);
265
266// Test std::__make_from_tuple_impl constraints.
267
268// reinterpret_cast
269LIBCPP_STATIC_ASSERT(!can_make_from_tuple_impl<int*, std::tuple<A*>>);
270LIBCPP_STATIC_ASSERT(can_make_from_tuple_impl<A*, std::tuple<A*>>);
271
272// const_cast
273LIBCPP_STATIC_ASSERT(!can_make_from_tuple_impl<char*, std::tuple<const char*>>);
274LIBCPP_STATIC_ASSERT(!can_make_from_tuple_impl<volatile char*, std::tuple<const volatile char*>>);
275LIBCPP_STATIC_ASSERT(can_make_from_tuple_impl<volatile char*, std::tuple<volatile char*>>);
276LIBCPP_STATIC_ASSERT(can_make_from_tuple_impl<char*, std::tuple<char*>>);
277LIBCPP_STATIC_ASSERT(can_make_from_tuple_impl<const char*, std::tuple<char*>>);
278LIBCPP_STATIC_ASSERT(can_make_from_tuple_impl<const volatile char*, std::tuple<volatile char*>>);
279
280// static_cast
281LIBCPP_STATIC_ASSERT(!can_make_from_tuple_impl<int, std::tuple<D>>);
282LIBCPP_STATIC_ASSERT(!can_make_from_tuple_impl<D, std::tuple<int>>);
283LIBCPP_STATIC_ASSERT(can_make_from_tuple_impl<long, std::tuple<int>>);
284LIBCPP_STATIC_ASSERT(can_make_from_tuple_impl<double, std::tuple<float>>);
285LIBCPP_STATIC_ASSERT(can_make_from_tuple_impl<float, std::tuple<double>>);
286
287} // namespace LWG3528
288
289int main(int, char**)
290{
291 test_constexpr_construction();
292 test_perfect_forwarding();
293 test_noexcept();
294
295 return 0;
296}
297

source code of libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp