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 | int main(int, char**) |
35 | { |
36 | { |
37 | std::tuple<> t = std::tuple_cat(); |
38 | ((void)t); // Prevent unused warning |
39 | } |
40 | { |
41 | std::tuple<> t1; |
42 | std::tuple<> t2 = std::tuple_cat(tpls&: t1); |
43 | ((void)t2); // Prevent unused warning |
44 | } |
45 | { |
46 | std::tuple<> t = std::tuple_cat(tpls: std::tuple<>()); |
47 | ((void)t); // Prevent unused warning |
48 | } |
49 | { |
50 | std::tuple<> t = std::tuple_cat(tpls: std::array<int, 0>()); |
51 | ((void)t); // Prevent unused warning |
52 | } |
53 | { |
54 | std::tuple<int> t1(1); |
55 | std::tuple<int> t = std::tuple_cat(tpls&: t1); |
56 | assert(std::get<0>(t) == 1); |
57 | } |
58 | |
59 | #if TEST_STD_VER > 11 |
60 | { |
61 | constexpr std::tuple<> t = std::tuple_cat(); |
62 | ((void)t); // Prevent unused warning |
63 | } |
64 | { |
65 | constexpr std::tuple<> t1; |
66 | constexpr std::tuple<> t2 = std::tuple_cat(t1); |
67 | ((void)t2); // Prevent unused warning |
68 | } |
69 | { |
70 | constexpr std::tuple<> t = std::tuple_cat(std::tuple<>()); |
71 | ((void)t); // Prevent unused warning |
72 | } |
73 | { |
74 | constexpr std::tuple<> t = std::tuple_cat(std::array<int, 0>()); |
75 | ((void)t); // Prevent unused warning |
76 | } |
77 | { |
78 | constexpr std::tuple<int> t1(1); |
79 | constexpr std::tuple<int> t = std::tuple_cat(t1); |
80 | static_assert(std::get<0>(t) == 1, "" ); |
81 | } |
82 | { |
83 | constexpr std::tuple<int> t1(1); |
84 | constexpr std::tuple<int, int> t = std::tuple_cat(t1, t1); |
85 | static_assert(std::get<0>(t) == 1, "" ); |
86 | static_assert(std::get<1>(t) == 1, "" ); |
87 | } |
88 | #endif |
89 | { |
90 | std::tuple<int, MoveOnly> t = |
91 | std::tuple_cat(std::tuple<int, MoveOnly>(1, 2)); |
92 | assert(std::get<0>(t) == 1); |
93 | assert(std::get<1>(t) == 2); |
94 | } |
95 | { |
96 | std::tuple<int, int, int> t = std::tuple_cat(tpls: std::array<int, 3>()); |
97 | assert(std::get<0>(t) == 0); |
98 | assert(std::get<1>(t) == 0); |
99 | assert(std::get<2>(t) == 0); |
100 | } |
101 | { |
102 | std::tuple<int, MoveOnly> t = std::tuple_cat(std::pair<int, MoveOnly>(2, 1)); |
103 | assert(std::get<0>(t) == 2); |
104 | assert(std::get<1>(t) == 1); |
105 | } |
106 | |
107 | { |
108 | std::tuple<> t1; |
109 | std::tuple<> t2; |
110 | std::tuple<> t3 = std::tuple_cat(tpls&: t1, tpls&: t2); |
111 | ((void)t3); // Prevent unused warning |
112 | } |
113 | { |
114 | std::tuple<> t1; |
115 | std::tuple<int> t2(2); |
116 | std::tuple<int> t3 = std::tuple_cat(tpls&: t1, tpls&: t2); |
117 | assert(std::get<0>(t3) == 2); |
118 | } |
119 | { |
120 | std::tuple<> t1; |
121 | std::tuple<int> t2(2); |
122 | std::tuple<int> t3 = std::tuple_cat(tpls&: t2, tpls&: t1); |
123 | assert(std::get<0>(t3) == 2); |
124 | } |
125 | { |
126 | std::tuple<int*> t1; |
127 | std::tuple<int> t2(2); |
128 | std::tuple<int*, int> t3 = std::tuple_cat(tpls&: t1, tpls&: t2); |
129 | assert(std::get<0>(t3) == nullptr); |
130 | assert(std::get<1>(t3) == 2); |
131 | } |
132 | { |
133 | std::tuple<int*> t1; |
134 | std::tuple<int> t2(2); |
135 | std::tuple<int, int*> t3 = std::tuple_cat(tpls&: t2, tpls&: t1); |
136 | assert(std::get<0>(t3) == 2); |
137 | assert(std::get<1>(t3) == nullptr); |
138 | } |
139 | { |
140 | std::tuple<int*> t1; |
141 | std::tuple<int, double> t2(2, 3.5); |
142 | std::tuple<int*, int, double> t3 = std::tuple_cat(tpls&: t1, tpls&: t2); |
143 | assert(std::get<0>(t3) == nullptr); |
144 | assert(std::get<1>(t3) == 2); |
145 | assert(std::get<2>(t3) == 3.5); |
146 | } |
147 | { |
148 | std::tuple<int*> t1; |
149 | std::tuple<int, double> t2(2, 3.5); |
150 | std::tuple<int, double, int*> t3 = std::tuple_cat(tpls&: t2, tpls&: t1); |
151 | assert(std::get<0>(t3) == 2); |
152 | assert(std::get<1>(t3) == 3.5); |
153 | assert(std::get<2>(t3) == nullptr); |
154 | } |
155 | { |
156 | std::tuple<int*, MoveOnly> t1(nullptr, 1); |
157 | std::tuple<int, double> t2(2, 3.5); |
158 | std::tuple<int*, MoveOnly, int, double> t3 = |
159 | std::tuple_cat(std::move(t1), t2); |
160 | assert(std::get<0>(t3) == nullptr); |
161 | assert(std::get<1>(t3) == 1); |
162 | assert(std::get<2>(t3) == 2); |
163 | assert(std::get<3>(t3) == 3.5); |
164 | } |
165 | { |
166 | std::tuple<int*, MoveOnly> t1(nullptr, 1); |
167 | std::tuple<int, double> t2(2, 3.5); |
168 | std::tuple<int, double, int*, MoveOnly> t3 = |
169 | std::tuple_cat(t2, std::move(t1)); |
170 | assert(std::get<0>(t3) == 2); |
171 | assert(std::get<1>(t3) == 3.5); |
172 | assert(std::get<2>(t3) == nullptr); |
173 | assert(std::get<3>(t3) == 1); |
174 | } |
175 | { |
176 | std::tuple<MoveOnly, MoveOnly> t1(1, 2); |
177 | std::tuple<int*, MoveOnly> t2(nullptr, 4); |
178 | std::tuple<MoveOnly, MoveOnly, int*, MoveOnly> t3 = |
179 | std::tuple_cat(std::move(t1), std::move(t2)); |
180 | assert(std::get<0>(t3) == 1); |
181 | assert(std::get<1>(t3) == 2); |
182 | assert(std::get<2>(t3) == nullptr); |
183 | assert(std::get<3>(t3) == 4); |
184 | } |
185 | |
186 | { |
187 | std::tuple<MoveOnly, MoveOnly> t1(1, 2); |
188 | std::tuple<int*, MoveOnly> t2(nullptr, 4); |
189 | std::tuple<MoveOnly, MoveOnly, int*, MoveOnly> t3 = |
190 | std::tuple_cat(std::tuple<>(), |
191 | std::move(t1), |
192 | std::move(t2)); |
193 | assert(std::get<0>(t3) == 1); |
194 | assert(std::get<1>(t3) == 2); |
195 | assert(std::get<2>(t3) == nullptr); |
196 | assert(std::get<3>(t3) == 4); |
197 | } |
198 | { |
199 | std::tuple<MoveOnly, MoveOnly> t1(1, 2); |
200 | std::tuple<int*, MoveOnly> t2(nullptr, 4); |
201 | std::tuple<MoveOnly, MoveOnly, int*, MoveOnly> t3 = |
202 | std::tuple_cat(std::move(t1), |
203 | std::tuple<>(), |
204 | std::move(t2)); |
205 | assert(std::get<0>(t3) == 1); |
206 | assert(std::get<1>(t3) == 2); |
207 | assert(std::get<2>(t3) == nullptr); |
208 | assert(std::get<3>(t3) == 4); |
209 | } |
210 | { |
211 | std::tuple<MoveOnly, MoveOnly> t1(1, 2); |
212 | std::tuple<int*, MoveOnly> t2(nullptr, 4); |
213 | std::tuple<MoveOnly, MoveOnly, int*, MoveOnly> t3 = |
214 | std::tuple_cat(std::move(t1), |
215 | std::move(t2), |
216 | std::tuple<>()); |
217 | assert(std::get<0>(t3) == 1); |
218 | assert(std::get<1>(t3) == 2); |
219 | assert(std::get<2>(t3) == nullptr); |
220 | assert(std::get<3>(t3) == 4); |
221 | } |
222 | { |
223 | std::tuple<MoveOnly, MoveOnly> t1(1, 2); |
224 | std::tuple<int*, MoveOnly> t2(nullptr, 4); |
225 | std::tuple<MoveOnly, MoveOnly, int*, MoveOnly, int> t3 = |
226 | std::tuple_cat(std::move(t1), |
227 | std::move(t2), |
228 | std::tuple<int>(5)); |
229 | assert(std::get<0>(t3) == 1); |
230 | assert(std::get<1>(t3) == 2); |
231 | assert(std::get<2>(t3) == nullptr); |
232 | assert(std::get<3>(t3) == 4); |
233 | assert(std::get<4>(t3) == 5); |
234 | } |
235 | { |
236 | // See bug #19616. |
237 | auto t1 = std::tuple_cat( |
238 | tpls: std::make_tuple(args: std::make_tuple(args: 1)), |
239 | tpls: std::make_tuple() |
240 | ); |
241 | assert(t1 == std::make_tuple(std::make_tuple(1))); |
242 | |
243 | auto t2 = std::tuple_cat( |
244 | tpls: std::make_tuple(args: std::make_tuple(args: 1)), |
245 | tpls: std::make_tuple(args: std::make_tuple(args: 2)) |
246 | ); |
247 | assert(t2 == std::make_tuple(std::make_tuple(1), std::make_tuple(2))); |
248 | } |
249 | { |
250 | int x = 101; |
251 | std::tuple<int, const int, int&, const int&, int&&> t(42, 101, x, x, std::move(x)); |
252 | const auto& ct = t; |
253 | std::tuple<int, const int, int&, const int&> t2(42, 101, x, x); |
254 | const auto& ct2 = t2; |
255 | |
256 | auto r = std::tuple_cat(tpls: std::move(t), tpls: std::move(ct), tpls&: t2, tpls: ct2); |
257 | |
258 | ASSERT_SAME_TYPE(decltype(r), std::tuple< |
259 | int, const int, int&, const int&, int&&, |
260 | int, const int, int&, const int&, int&&, |
261 | int, const int, int&, const int&, |
262 | int, const int, int&, const int&>); |
263 | ((void)r); |
264 | } |
265 | { |
266 | std::tuple<NS::Namespaced> t1(NS::Namespaced{.i: 1}); |
267 | std::tuple<NS::Namespaced> t = std::tuple_cat(tpls&: t1); |
268 | std::tuple<NS::Namespaced, NS::Namespaced> t2 = |
269 | std::tuple_cat(tpls&: t1, tpls&: t1); |
270 | assert(std::get<0>(t).i == 1); |
271 | assert(std::get<0>(t2).i == 1); |
272 | } |
273 | return 0; |
274 | } |
275 | |