xref: /llvm-project/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp (revision 31a9a4b83720af79110941824abe28fc6ff42355)
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