xref: /llvm-project/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp (revision 31cbe0f240f660f15602c96b787c58a26f17e179)
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 // std::array is explicitly allowed to be initialized with A a = { init-list };.
25 // Disable the missing braces warning for this reason.
26 #include "disable_missing_braces_warning.h"
27 
28 template <class Tuple>
29 struct ConstexprConstructibleFromTuple {
30   template <class ...Args>
31   explicit constexpr ConstexprConstructibleFromTuple(Args&&... xargs)
32       : args{std::forward<Args>(xargs)...} {}
33   Tuple args;
34 };
35 
36 template <class TupleLike>
37 struct ConstructibleFromTuple;
38 
39 template <template <class ...> class Tuple, class ...Types>
40 struct ConstructibleFromTuple<Tuple<Types...>> {
41   template <class ...Args>
42   explicit ConstructibleFromTuple(Args&&... xargs)
43       : args(xargs...),
44         arg_types(&makeArgumentID<Args&&...>())
45   {}
46   Tuple<std::decay_t<Types>...> args;
47   TypeID const* arg_types;
48 };
49 
50 template <class Tp, size_t N>
51 struct ConstructibleFromTuple<std::array<Tp, N>> {
52 template <class ...Args>
53   explicit ConstructibleFromTuple(Args&&... xargs)
54       : args{xargs...},
55         arg_types(&makeArgumentID<Args&&...>())
56   {}
57   std::array<Tp, N> args;
58   TypeID const* arg_types;
59 };
60 
61 template <class Tuple>
62 constexpr bool do_constexpr_test(Tuple&& tup) {
63     using RawTuple = std::decay_t<Tuple>;
64     using Tp = ConstexprConstructibleFromTuple<RawTuple>;
65     return std::make_from_tuple<Tp>(std::forward<Tuple>(tup)).args == tup;
66 }
67 
68 // Needed by do_forwarding_test() since it compares pairs of different types.
69 template <class T1, class T2, class U1, class U2>
70 inline bool operator==(const std::pair<T1, T2>& lhs, const std::pair<U1, U2>& rhs) {
71     return lhs.first == rhs.first && lhs.second == rhs.second;
72 }
73 
74 template <class ...ExpectTypes, class Tuple>
75 bool do_forwarding_test(Tuple&& tup) {
76     using RawTuple = std::decay_t<Tuple>;
77     using Tp = ConstructibleFromTuple<RawTuple>;
78     const Tp value = std::make_from_tuple<Tp>(std::forward<Tuple>(tup));
79     return value.args == tup
80         && value.arg_types == &makeArgumentID<ExpectTypes...>();
81 }
82 
83 void test_constexpr_construction() {
84     {
85         constexpr std::tuple<> tup;
86         static_assert(do_constexpr_test(tup), "");
87     }
88     {
89         constexpr std::tuple<int> tup(42);
90         static_assert(do_constexpr_test(tup), "");
91     }
92     {
93         constexpr std::tuple<int, long, void*> tup(42, 101, nullptr);
94         static_assert(do_constexpr_test(tup), "");
95     }
96     {
97         constexpr std::pair<int, const char*> p(42, "hello world");
98         static_assert(do_constexpr_test(p), "");
99     }
100     {
101         using Tuple = std::array<int, 3>;
102         using ValueTp = ConstexprConstructibleFromTuple<Tuple>;
103         constexpr Tuple arr = {42, 101, -1};
104         constexpr ValueTp value = std::make_from_tuple<ValueTp>(arr);
105         static_assert(value.args[0] == arr[0] && value.args[1] == arr[1]
106             && value.args[2] == arr[2], "");
107     }
108 }
109 
110 void test_perfect_forwarding() {
111     {
112         using Tup = std::tuple<>;
113         Tup tup;
114         Tup const& ctup = tup;
115         assert(do_forwarding_test<>(tup));
116         assert(do_forwarding_test<>(ctup));
117     }
118     {
119         using Tup = std::tuple<int>;
120         Tup tup(42);
121         Tup const& ctup = tup;
122         assert(do_forwarding_test<int&>(tup));
123         assert(do_forwarding_test<int const&>(ctup));
124         assert(do_forwarding_test<int&&>(std::move(tup)));
125         assert(do_forwarding_test<int const&&>(std::move(ctup)));
126     }
127     {
128         using Tup = std::tuple<int&, const char*, unsigned&&>;
129         int x = 42;
130         unsigned y = 101;
131         Tup tup(x, "hello world", std::move(y));
132         Tup const& ctup = tup;
133         assert((do_forwarding_test<int&, const char*&, unsigned&>(tup)));
134         assert((do_forwarding_test<int&, const char* const&, unsigned &>(ctup)));
135         assert((do_forwarding_test<int&, const char*&&, unsigned&&>(std::move(tup))));
136         assert((do_forwarding_test<int&, const char* const&&, unsigned &&>(std::move(ctup))));
137     }
138     // test with pair<T, U>
139     {
140         using Tup = std::pair<int&, const char*>;
141         int x = 42;
142         Tup tup(x, "hello world");
143         Tup const& ctup = tup;
144         assert((do_forwarding_test<int&, const char*&>(tup)));
145         assert((do_forwarding_test<int&, const char* const&>(ctup)));
146         assert((do_forwarding_test<int&, const char*&&>(std::move(tup))));
147         assert((do_forwarding_test<int&, const char* const&&>(std::move(ctup))));
148     }
149     // test with array<T, I>
150     {
151         using Tup = std::array<int, 3>;
152         Tup tup = {42, 101, -1};
153         Tup const& ctup = tup;
154         assert((do_forwarding_test<int&, int&, int&>(tup)));
155         assert((do_forwarding_test<int const&, int const&, int const&>(ctup)));
156         assert((do_forwarding_test<int&&, int&&, int&&>(std::move(tup))));
157         assert((do_forwarding_test<int const&&, int const&&, int const&&>(std::move(ctup))));
158     }
159 }
160 
161 void test_noexcept() {
162     struct NothrowMoveable {
163       NothrowMoveable() = default;
164       NothrowMoveable(NothrowMoveable const&) {}
165       NothrowMoveable(NothrowMoveable&&) noexcept {}
166     };
167     struct TestType {
168       TestType(int, NothrowMoveable) noexcept {}
169       TestType(int, int, int) noexcept(false) {}
170       TestType(long, long, long) noexcept {}
171     };
172     {
173         using Tuple = std::tuple<int, NothrowMoveable>;
174         Tuple tup; ((void)tup);
175         Tuple const& ctup = tup; ((void)ctup);
176         ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(ctup));
177         LIBCPP_ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(std::move(tup)));
178     }
179     {
180         using Tuple = std::pair<int, NothrowMoveable>;
181         Tuple tup; ((void)tup);
182         Tuple const& ctup = tup; ((void)ctup);
183         ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(ctup));
184         LIBCPP_ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(std::move(tup)));
185     }
186     {
187         using Tuple = std::tuple<int, int, int>;
188         Tuple tup; ((void)tup);
189         ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(tup));
190     }
191     {
192         using Tuple = std::tuple<long, long, long>;
193         Tuple tup; ((void)tup);
194         LIBCPP_ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(tup));
195     }
196     {
197         using Tuple = std::array<int, 3>;
198         Tuple tup; ((void)tup);
199         ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(tup));
200     }
201     {
202         using Tuple = std::array<long, 3>;
203         Tuple tup; ((void)tup);
204         LIBCPP_ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(tup));
205     }
206 }
207 
208 int main(int, char**)
209 {
210     test_constexpr_construction();
211     test_perfect_forwarding();
212     test_noexcept();
213 
214   return 0;
215 }
216