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>
ConstexprConstructibleFromTupleConstexprConstructibleFromTuple27 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>
ConstructibleFromTupleConstructibleFromTuple38 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>
ConstructibleFromTupleConstructibleFromTuple49 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>
do_constexpr_test(Tuple && tup)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>
operator ==(const std::pair<T1,T2> & lhs,const std::pair<U1,U2> & rhs)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>
do_forwarding_test(Tuple && tup)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
test_constexpr_construction()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
test_perfect_forwarding()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
test_noexcept()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
main(int,char **)204 int main(int, char**)
205 {
206 test_constexpr_construction();
207 test_perfect_forwarding();
208 test_noexcept();
209
210 return 0;
211 }
212