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
26namespace NS {
27struct Namespaced {
28 int i;
29};
30template<typename ...Ts>
31void forward_as_tuple(Ts...) = delete;
32}
33
34// https://github.com/llvm/llvm-project/issues/41034
35struct Unconstrained {
36 int data;
37 template <typename Arg>
38 TEST_CONSTEXPR_CXX14 Unconstrained(Arg arg) : data(arg) {}
39};
40
41TEST_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(tpls: std::tuple<Unconstrained>(Unconstrained(6)));
49 assert(std::get<0>(tup).data == 6);
50 }
51 {
52 auto tup = std::tuple_cat(tpls: std::tuple<Unconstrained>(Unconstrained(7)), tpls: 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
76int 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(tpls&: t1);
85 ((void)t2); // Prevent unused warning
86 }
87 {
88 std::tuple<> t = std::tuple_cat(tpls: std::tuple<>());
89 ((void)t); // Prevent unused warning
90 }
91 {
92 std::tuple<> t = std::tuple_cat(tpls: 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(tpls&: 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(tpls: 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(tpls&: t1, tpls&: 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(tpls&: t1, tpls&: 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(tpls&: t2, tpls&: 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(tpls&: t1, tpls&: 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(tpls&: t2, tpls&: 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(tpls&: t1, tpls&: 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(tpls&: t2, tpls&: 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 tpls: std::make_tuple(args: std::make_tuple(args: 1)),
281 tpls: std::make_tuple()
282 );
283 assert(t1 == std::make_tuple(std::make_tuple(1)));
284
285 auto t2 = std::tuple_cat(
286 tpls: std::make_tuple(args: std::make_tuple(args: 1)),
287 tpls: std::make_tuple(args: std::make_tuple(args: 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(tpls: std::move(t), tpls: std::move(ct), tpls&: t2, tpls: 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{.i: 1});
309 std::tuple<NS::Namespaced> t = std::tuple_cat(tpls&: t1);
310 std::tuple<NS::Namespaced, NS::Namespaced> t2 =
311 std::tuple_cat(tpls&: t1, tpls&: 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

source code of libcxx/test/std/utilities/tuple/tuple.tuple/tuple.creation/tuple_cat.pass.cpp