xref: /llvm-project/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp (revision 9fb3669429a8bc59622c26ab6f5cf6926ee97e7d)
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, 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 // Needed by do_forwarding_test() since it compares pairs of different types.
65 template <class T1, class T2, class U1, class U2>
66 inline bool operator==(const std::pair<T1, T2>& lhs, const std::pair<U1, U2>& rhs) {
67     return lhs.first == rhs.first && lhs.second == rhs.second;
68 }
69 
70 template <class ...ExpectTypes, class Tuple>
71 bool do_forwarding_test(Tuple&& tup) {
72     using RawTuple = std::decay_t<Tuple>;
73     using Tp = ConstructibleFromTuple<RawTuple>;
74     const Tp value = std::make_from_tuple<Tp>(std::forward<Tuple>(tup));
75     return value.args == tup
76         && value.arg_types == &makeArgumentID<ExpectTypes...>();
77 }
78 
79 void test_constexpr_construction() {
80     {
81         constexpr std::tuple<> tup;
82         static_assert(do_constexpr_test(tup), "");
83     }
84     {
85         constexpr std::tuple<int> tup(42);
86         static_assert(do_constexpr_test(tup), "");
87     }
88     {
89         constexpr std::tuple<int, long, void*> tup(42, 101, nullptr);
90         static_assert(do_constexpr_test(tup), "");
91     }
92     {
93         constexpr std::pair<int, const char*> p(42, "hello world");
94         static_assert(do_constexpr_test(p), "");
95     }
96     {
97         using Tuple = std::array<int, 3>;
98         using ValueTp = ConstexprConstructibleFromTuple<Tuple>;
99         constexpr Tuple arr = {42, 101, -1};
100         constexpr ValueTp value = std::make_from_tuple<ValueTp>(arr);
101         static_assert(value.args[0] == arr[0] && value.args[1] == arr[1]
102             && value.args[2] == arr[2], "");
103     }
104 }
105 
106 void test_perfect_forwarding() {
107     {
108         using Tup = std::tuple<>;
109         Tup tup;
110         Tup const& ctup = tup;
111         assert(do_forwarding_test<>(tup));
112         assert(do_forwarding_test<>(ctup));
113     }
114     {
115         using Tup = std::tuple<int>;
116         Tup tup(42);
117         Tup const& ctup = tup;
118         assert(do_forwarding_test<int&>(tup));
119         assert(do_forwarding_test<int const&>(ctup));
120         assert(do_forwarding_test<int&&>(std::move(tup)));
121         assert(do_forwarding_test<int const&&>(std::move(ctup)));
122     }
123     {
124         using Tup = std::tuple<int&, const char*, unsigned&&>;
125         int x = 42;
126         unsigned y = 101;
127         Tup tup(x, "hello world", std::move(y));
128         Tup const& ctup = tup;
129         assert((do_forwarding_test<int&, const char*&, unsigned&>(tup)));
130         assert((do_forwarding_test<int&, const char* const&, unsigned &>(ctup)));
131         assert((do_forwarding_test<int&, const char*&&, unsigned&&>(std::move(tup))));
132         assert((do_forwarding_test<int&, const char* const&&, unsigned &&>(std::move(ctup))));
133     }
134     // test with pair<T, U>
135     {
136         using Tup = std::pair<int&, const char*>;
137         int x = 42;
138         Tup tup(x, "hello world");
139         Tup const& ctup = tup;
140         assert((do_forwarding_test<int&, const char*&>(tup)));
141         assert((do_forwarding_test<int&, const char* const&>(ctup)));
142         assert((do_forwarding_test<int&, const char*&&>(std::move(tup))));
143         assert((do_forwarding_test<int&, const char* const&&>(std::move(ctup))));
144     }
145     // test with array<T, I>
146     {
147         using Tup = std::array<int, 3>;
148         Tup tup = {42, 101, -1};
149         Tup const& ctup = tup;
150         assert((do_forwarding_test<int&, int&, int&>(tup)));
151         assert((do_forwarding_test<int const&, int const&, int const&>(ctup)));
152         assert((do_forwarding_test<int&&, int&&, int&&>(std::move(tup))));
153         assert((do_forwarding_test<int const&&, int const&&, int const&&>(std::move(ctup))));
154     }
155 }
156 
157 void test_noexcept() {
158     struct NothrowMoveable {
159       NothrowMoveable() = default;
160       NothrowMoveable(NothrowMoveable const&) {}
161       NothrowMoveable(NothrowMoveable&&) noexcept {}
162     };
163     struct TestType {
164       TestType(int, NothrowMoveable) noexcept {}
165       TestType(int, int, int) noexcept(false) {}
166       TestType(long, long, long) noexcept {}
167     };
168     {
169         using Tuple = std::tuple<int, NothrowMoveable>;
170         Tuple tup; ((void)tup);
171         Tuple const& ctup = tup; ((void)ctup);
172         ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(ctup));
173         LIBCPP_ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(std::move(tup)));
174     }
175     {
176         using Tuple = std::pair<int, NothrowMoveable>;
177         Tuple tup; ((void)tup);
178         Tuple const& ctup = tup; ((void)ctup);
179         ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(ctup));
180         LIBCPP_ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(std::move(tup)));
181     }
182     {
183         using Tuple = std::tuple<int, int, int>;
184         Tuple tup; ((void)tup);
185         ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(tup));
186     }
187     {
188         using Tuple = std::tuple<long, long, long>;
189         Tuple tup; ((void)tup);
190         LIBCPP_ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(tup));
191     }
192     {
193         using Tuple = std::array<int, 3>;
194         Tuple tup; ((void)tup);
195         ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(tup));
196     }
197     {
198         using Tuple = std::array<long, 3>;
199         Tuple tup; ((void)tup);
200         LIBCPP_ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(tup));
201     }
202 }
203 
204 int main(int, char**)
205 {
206     test_constexpr_construction();
207     test_perfect_forwarding();
208     test_noexcept();
209 
210   return 0;
211 }
212