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