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

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