xref: /llvm-project/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.creation/tuple_cat.pass.cpp (revision e03c435d2a4900eb442c1f68b044c21cbc89acbe)
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 // <tuple>
10 
11 // template <class... Types> class tuple;
12 
13 // template <class... Tuples> tuple<CTypes...> tuple_cat(Tuples&&... tpls);
14 
15 // UNSUPPORTED: c++03
16 
17 #include <tuple>
18 #include <utility>
19 #include <array>
20 #include <string>
21 #include <cassert>
22 
23 #include "test_macros.h"
24 #include "MoveOnly.h"
25 
26 namespace NS {
27 struct Namespaced {
28   int i;
29 };
30 template<typename ...Ts>
31 void forward_as_tuple(Ts...) = delete;
32 }
33 
34 // https://github.com/llvm/llvm-project/issues/41034
35 struct Unconstrained {
36   int data;
37   template <typename Arg>
38   TEST_CONSTEXPR_CXX14 Unconstrained(Arg arg) : data(arg) {}
39 };
40 
41 TEST_CONSTEXPR_CXX14 bool test_tuple_cat_with_unconstrained_constructor() {
42   {
43     auto tup_src = std::tuple<Unconstrained>(Unconstrained(5));
44     auto tup     = std::tuple_cat(tup_src);
45     assert(std::get<0>(tup).data == 5);
46   }
47   {
48     auto tup = std::tuple_cat(std::tuple<Unconstrained>(Unconstrained(6)));
49     assert(std::get<0>(tup).data == 6);
50   }
51   {
52     auto tup = std::tuple_cat(std::tuple<Unconstrained>(Unconstrained(7)), std::tuple<>());
53     assert(std::get<0>(tup).data == 7);
54   }
55 #if TEST_STD_VER >= 17
56   {
57     auto tup_src = std::tuple(Unconstrained(8));
58     auto tup     = std::tuple_cat(tup_src);
59     ASSERT_SAME_TYPE(decltype(tup), std::tuple<Unconstrained>);
60     assert(std::get<0>(tup).data == 8);
61   }
62   {
63     auto tup = std::tuple_cat(std::tuple(Unconstrained(9)));
64     ASSERT_SAME_TYPE(decltype(tup), std::tuple<Unconstrained>);
65     assert(std::get<0>(tup).data == 9);
66   }
67   {
68     auto tup = std::tuple_cat(std::tuple(Unconstrained(10)), std::tuple());
69     ASSERT_SAME_TYPE(decltype(tup), std::tuple<Unconstrained>);
70     assert(std::get<0>(tup).data == 10);
71   }
72 #endif
73   return true;
74 }
75 
76 int main(int, char**)
77 {
78     {
79         std::tuple<> t = std::tuple_cat();
80         ((void)t); // Prevent unused warning
81     }
82     {
83         std::tuple<> t1;
84         std::tuple<> t2 = std::tuple_cat(t1);
85         ((void)t2); // Prevent unused warning
86     }
87     {
88         std::tuple<> t = std::tuple_cat(std::tuple<>());
89         ((void)t); // Prevent unused warning
90     }
91     {
92         std::tuple<> t = std::tuple_cat(std::array<int, 0>());
93         ((void)t); // Prevent unused warning
94     }
95     {
96         std::tuple<int> t1(1);
97         std::tuple<int> t = std::tuple_cat(t1);
98         assert(std::get<0>(t) == 1);
99     }
100 
101 #if TEST_STD_VER > 11
102     {
103         constexpr std::tuple<> t = std::tuple_cat();
104         ((void)t); // Prevent unused warning
105     }
106     {
107         constexpr std::tuple<> t1;
108         constexpr std::tuple<> t2 = std::tuple_cat(t1);
109         ((void)t2); // Prevent unused warning
110     }
111     {
112         constexpr std::tuple<> t = std::tuple_cat(std::tuple<>());
113         ((void)t); // Prevent unused warning
114     }
115     {
116         constexpr std::tuple<> t = std::tuple_cat(std::array<int, 0>());
117         ((void)t); // Prevent unused warning
118     }
119     {
120         constexpr std::tuple<int> t1(1);
121         constexpr std::tuple<int> t = std::tuple_cat(t1);
122         static_assert(std::get<0>(t) == 1, "");
123     }
124     {
125         constexpr std::tuple<int> t1(1);
126         constexpr std::tuple<int, int> t = std::tuple_cat(t1, t1);
127         static_assert(std::get<0>(t) == 1, "");
128         static_assert(std::get<1>(t) == 1, "");
129     }
130 #endif
131     {
132         std::tuple<int, MoveOnly> t =
133                                 std::tuple_cat(std::tuple<int, MoveOnly>(1, 2));
134         assert(std::get<0>(t) == 1);
135         assert(std::get<1>(t) == 2);
136     }
137     {
138         std::tuple<int, int, int> t = std::tuple_cat(std::array<int, 3>());
139         assert(std::get<0>(t) == 0);
140         assert(std::get<1>(t) == 0);
141         assert(std::get<2>(t) == 0);
142     }
143     {
144         std::tuple<int, MoveOnly> t = std::tuple_cat(std::pair<int, MoveOnly>(2, 1));
145         assert(std::get<0>(t) == 2);
146         assert(std::get<1>(t) == 1);
147     }
148 
149     {
150         std::tuple<> t1;
151         std::tuple<> t2;
152         std::tuple<> t3 = std::tuple_cat(t1, t2);
153         ((void)t3); // Prevent unused warning
154     }
155     {
156         std::tuple<> t1;
157         std::tuple<int> t2(2);
158         std::tuple<int> t3 = std::tuple_cat(t1, t2);
159         assert(std::get<0>(t3) == 2);
160     }
161     {
162         std::tuple<> t1;
163         std::tuple<int> t2(2);
164         std::tuple<int> t3 = std::tuple_cat(t2, t1);
165         assert(std::get<0>(t3) == 2);
166     }
167     {
168         std::tuple<int*> t1;
169         std::tuple<int> t2(2);
170         std::tuple<int*, int> t3 = std::tuple_cat(t1, t2);
171         assert(std::get<0>(t3) == nullptr);
172         assert(std::get<1>(t3) == 2);
173     }
174     {
175         std::tuple<int*> t1;
176         std::tuple<int> t2(2);
177         std::tuple<int, int*> t3 = std::tuple_cat(t2, t1);
178         assert(std::get<0>(t3) == 2);
179         assert(std::get<1>(t3) == nullptr);
180     }
181     {
182         std::tuple<int*> t1;
183         std::tuple<int, double> t2(2, 3.5);
184         std::tuple<int*, int, double> t3 = std::tuple_cat(t1, t2);
185         assert(std::get<0>(t3) == nullptr);
186         assert(std::get<1>(t3) == 2);
187         assert(std::get<2>(t3) == 3.5);
188     }
189     {
190         std::tuple<int*> t1;
191         std::tuple<int, double> t2(2, 3.5);
192         std::tuple<int, double, int*> t3 = std::tuple_cat(t2, t1);
193         assert(std::get<0>(t3) == 2);
194         assert(std::get<1>(t3) == 3.5);
195         assert(std::get<2>(t3) == nullptr);
196     }
197     {
198         std::tuple<int*, MoveOnly> t1(nullptr, 1);
199         std::tuple<int, double> t2(2, 3.5);
200         std::tuple<int*, MoveOnly, int, double> t3 =
201                                               std::tuple_cat(std::move(t1), t2);
202         assert(std::get<0>(t3) == nullptr);
203         assert(std::get<1>(t3) == 1);
204         assert(std::get<2>(t3) == 2);
205         assert(std::get<3>(t3) == 3.5);
206     }
207     {
208         std::tuple<int*, MoveOnly> t1(nullptr, 1);
209         std::tuple<int, double> t2(2, 3.5);
210         std::tuple<int, double, int*, MoveOnly> t3 =
211                                               std::tuple_cat(t2, std::move(t1));
212         assert(std::get<0>(t3) == 2);
213         assert(std::get<1>(t3) == 3.5);
214         assert(std::get<2>(t3) == nullptr);
215         assert(std::get<3>(t3) == 1);
216     }
217     {
218         std::tuple<MoveOnly, MoveOnly> t1(1, 2);
219         std::tuple<int*, MoveOnly> t2(nullptr, 4);
220         std::tuple<MoveOnly, MoveOnly, int*, MoveOnly> t3 =
221                                    std::tuple_cat(std::move(t1), std::move(t2));
222         assert(std::get<0>(t3) == 1);
223         assert(std::get<1>(t3) == 2);
224         assert(std::get<2>(t3) == nullptr);
225         assert(std::get<3>(t3) == 4);
226     }
227 
228     {
229         std::tuple<MoveOnly, MoveOnly> t1(1, 2);
230         std::tuple<int*, MoveOnly> t2(nullptr, 4);
231         std::tuple<MoveOnly, MoveOnly, int*, MoveOnly> t3 =
232                                    std::tuple_cat(std::tuple<>(),
233                                                   std::move(t1),
234                                                   std::move(t2));
235         assert(std::get<0>(t3) == 1);
236         assert(std::get<1>(t3) == 2);
237         assert(std::get<2>(t3) == nullptr);
238         assert(std::get<3>(t3) == 4);
239     }
240     {
241         std::tuple<MoveOnly, MoveOnly> t1(1, 2);
242         std::tuple<int*, MoveOnly> t2(nullptr, 4);
243         std::tuple<MoveOnly, MoveOnly, int*, MoveOnly> t3 =
244                                    std::tuple_cat(std::move(t1),
245                                                   std::tuple<>(),
246                                                   std::move(t2));
247         assert(std::get<0>(t3) == 1);
248         assert(std::get<1>(t3) == 2);
249         assert(std::get<2>(t3) == nullptr);
250         assert(std::get<3>(t3) == 4);
251     }
252     {
253         std::tuple<MoveOnly, MoveOnly> t1(1, 2);
254         std::tuple<int*, MoveOnly> t2(nullptr, 4);
255         std::tuple<MoveOnly, MoveOnly, int*, MoveOnly> t3 =
256                                    std::tuple_cat(std::move(t1),
257                                                   std::move(t2),
258                                                   std::tuple<>());
259         assert(std::get<0>(t3) == 1);
260         assert(std::get<1>(t3) == 2);
261         assert(std::get<2>(t3) == nullptr);
262         assert(std::get<3>(t3) == 4);
263     }
264     {
265         std::tuple<MoveOnly, MoveOnly> t1(1, 2);
266         std::tuple<int*, MoveOnly> t2(nullptr, 4);
267         std::tuple<MoveOnly, MoveOnly, int*, MoveOnly, int> t3 =
268                                    std::tuple_cat(std::move(t1),
269                                                   std::move(t2),
270                                                   std::tuple<int>(5));
271         assert(std::get<0>(t3) == 1);
272         assert(std::get<1>(t3) == 2);
273         assert(std::get<2>(t3) == nullptr);
274         assert(std::get<3>(t3) == 4);
275         assert(std::get<4>(t3) == 5);
276     }
277     {
278         // See bug #19616.
279         auto t1 = std::tuple_cat(
280             std::make_tuple(std::make_tuple(1)),
281             std::make_tuple()
282         );
283         assert(t1 == std::make_tuple(std::make_tuple(1)));
284 
285         auto t2 = std::tuple_cat(
286             std::make_tuple(std::make_tuple(1)),
287             std::make_tuple(std::make_tuple(2))
288         );
289         assert(t2 == std::make_tuple(std::make_tuple(1), std::make_tuple(2)));
290     }
291     {
292         int x = 101;
293         std::tuple<int, const int, int&, const int&, int&&> t(42, 101, x, x, std::move(x));
294         const auto& ct = t;
295         std::tuple<int, const int, int&, const int&> t2(42, 101, x, x);
296         const auto& ct2 = t2;
297 
298         auto r = std::tuple_cat(std::move(t), std::move(ct), t2, ct2);
299 
300         ASSERT_SAME_TYPE(decltype(r), std::tuple<
301             int, const int, int&, const int&, int&&,
302             int, const int, int&, const int&, int&&,
303             int, const int, int&, const int&,
304             int, const int, int&, const int&>);
305         ((void)r);
306     }
307     {
308         std::tuple<NS::Namespaced> t1(NS::Namespaced{1});
309         std::tuple<NS::Namespaced> t = std::tuple_cat(t1);
310         std::tuple<NS::Namespaced, NS::Namespaced> t2 =
311             std::tuple_cat(t1, t1);
312         assert(std::get<0>(t).i == 1);
313         assert(std::get<0>(t2).i == 1);
314     }
315     // See https://github.com/llvm/llvm-project/issues/41034
316     {
317       test_tuple_cat_with_unconstrained_constructor();
318 #if TEST_STD_VER >= 14
319       static_assert(test_tuple_cat_with_unconstrained_constructor(), "");
320 #endif
321     }
322 
323     return 0;
324 }
325