]>
Commit | Line | Data |
---|---|---|
b32b8144 | 1 | // Copyright Louis Dionne 2013-2017 |
7c673cae FG |
2 | // Distributed under the Boost Software License, Version 1.0. |
3 | // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) | |
4 | ||
5 | #include <boost/hana/assert.hpp> | |
6 | #include <boost/hana/equal.hpp> | |
7 | #include <boost/hana/functional/apply.hpp> | |
8 | ||
9 | #include <laws/base.hpp> | |
10 | #include <support/tracked.hpp> | |
11 | ||
12 | #include <type_traits> | |
13 | #include <utility> | |
14 | namespace hana = boost::hana; | |
15 | ||
16 | ||
17 | template <int i = 0> | |
18 | struct nonpod : Tracked { | |
19 | nonpod() : Tracked{i} { } | |
20 | }; | |
21 | ||
22 | struct NonCopyable { | |
23 | NonCopyable() = default; | |
24 | NonCopyable(NonCopyable const&) = delete; | |
25 | NonCopyable& operator=(NonCopyable const&) = delete; | |
26 | }; | |
27 | ||
28 | struct TestClass { | |
29 | explicit TestClass(int x) : data(x) { } | |
30 | TestClass(TestClass const&) = delete; | |
31 | TestClass& operator=(TestClass const&) = delete; | |
32 | ||
33 | int& operator()(NonCopyable&&) & { return data; } | |
34 | int const& operator()(NonCopyable&&) const & { return data; } | |
35 | int volatile& operator()(NonCopyable&&) volatile & { return data; } | |
36 | int const volatile& operator()(NonCopyable&&) const volatile & { return data; } | |
37 | ||
38 | int&& operator()(NonCopyable&&) && { return std::move(data); } | |
39 | int const&& operator()(NonCopyable&&) const && { return std::move(data); } | |
40 | int volatile&& operator()(NonCopyable&&) volatile && { return std::move(data); } | |
41 | int const volatile&& operator()(NonCopyable&&) const volatile && { return std::move(data); } | |
42 | ||
43 | int data; | |
44 | }; | |
45 | ||
46 | struct DerivedFromTestClass : TestClass { | |
47 | explicit DerivedFromTestClass(int x) : TestClass(x) { } | |
48 | }; | |
49 | ||
50 | ||
51 | template <typename Signature, typename Expect, typename Functor> | |
52 | void test_b12(Functor&& f) { | |
53 | // Create the callable object. | |
54 | using ClassFunc = Signature TestClass::*; | |
55 | ClassFunc func_ptr = &TestClass::operator(); | |
56 | ||
57 | // Create the dummy arg. | |
58 | NonCopyable arg; | |
59 | ||
60 | // Check that the deduced return type of invoke is what is expected. | |
61 | using DeducedReturnType = decltype( | |
62 | hana::apply(func_ptr, std::forward<Functor>(f), std::move(arg)) | |
63 | ); | |
64 | static_assert(std::is_same<DeducedReturnType, Expect>::value, ""); | |
65 | ||
7c673cae FG |
66 | // Run invoke and check the return value. |
67 | DeducedReturnType ret = hana::apply(func_ptr, std::forward<Functor>(f), std::move(arg)); | |
68 | BOOST_HANA_RUNTIME_CHECK(ret == 42); | |
69 | } | |
70 | ||
71 | template <typename Expect, typename Functor> | |
72 | void test_b34(Functor&& f) { | |
73 | // Create the callable object. | |
74 | using ClassFunc = int TestClass::*; | |
75 | ClassFunc func_ptr = &TestClass::data; | |
76 | ||
77 | // Check that the deduced return type of invoke is what is expected. | |
78 | using DeducedReturnType = decltype( | |
79 | hana::apply(func_ptr, std::forward<Functor>(f)) | |
80 | ); | |
81 | static_assert(std::is_same<DeducedReturnType, Expect>::value, ""); | |
82 | ||
7c673cae FG |
83 | // Run invoke and check the return value. |
84 | DeducedReturnType ret = hana::apply(func_ptr, std::forward<Functor>(f)); | |
85 | BOOST_HANA_RUNTIME_CHECK(ret == 42); | |
86 | } | |
87 | ||
88 | template <typename Expect, typename Functor> | |
89 | void test_b5(Functor&& f) { | |
90 | NonCopyable arg; | |
91 | ||
92 | // Check that the deduced return type of invoke is what is expected. | |
93 | using DeducedReturnType = decltype( | |
94 | hana::apply(std::forward<Functor>(f), std::move(arg)) | |
95 | ); | |
96 | static_assert(std::is_same<DeducedReturnType, Expect>::value, ""); | |
97 | ||
7c673cae FG |
98 | // Run invoke and check the return value. |
99 | DeducedReturnType ret = hana::apply(std::forward<Functor>(f), std::move(arg)); | |
100 | BOOST_HANA_RUNTIME_CHECK(ret == 42); | |
101 | } | |
102 | ||
103 | int& foo(NonCopyable&&) { | |
104 | static int data = 42; | |
105 | return data; | |
106 | } | |
107 | ||
108 | int main() { | |
109 | // Test normal usage with a function object | |
110 | { | |
111 | hana::test::_injection<0> f{}; | |
112 | using hana::test::ct_eq; | |
113 | ||
114 | BOOST_HANA_CONSTANT_CHECK(hana::equal( | |
115 | hana::apply(f), | |
116 | f() | |
117 | )); | |
118 | BOOST_HANA_CONSTANT_CHECK(hana::equal( | |
119 | hana::apply(f, ct_eq<0>{}), | |
120 | f(ct_eq<0>{}) | |
121 | )); | |
122 | BOOST_HANA_CONSTANT_CHECK(hana::equal( | |
123 | hana::apply(f, ct_eq<0>{}, ct_eq<1>{}), | |
124 | f(ct_eq<0>{}, ct_eq<1>{}) | |
125 | )); | |
126 | BOOST_HANA_CONSTANT_CHECK(hana::equal( | |
127 | hana::apply(f, ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}), | |
128 | f(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}) | |
129 | )); | |
130 | BOOST_HANA_CONSTANT_CHECK(hana::equal( | |
131 | hana::apply(f, ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{}), | |
132 | f(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{}) | |
133 | )); | |
134 | ||
135 | // Make sure we can use apply with non-PODs | |
136 | hana::apply(f, nonpod<>{}); | |
137 | } | |
138 | ||
139 | // Bullets 1 & 2 in the standard | |
140 | { | |
141 | TestClass cl(42); | |
142 | test_b12<int&(NonCopyable&&) &, int&>(cl); | |
143 | test_b12<int const&(NonCopyable&&) const &, int const&>(cl); | |
144 | test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(cl); | |
145 | test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(cl); | |
146 | ||
147 | test_b12<int&&(NonCopyable&&) &&, int&&>(std::move(cl)); | |
148 | test_b12<int const&&(NonCopyable&&) const &&, int const&&>(std::move(cl)); | |
149 | test_b12<int volatile&&(NonCopyable&&) volatile &&, int volatile&&>(std::move(cl)); | |
150 | test_b12<int const volatile&&(NonCopyable&&) const volatile &&, int const volatile&&>(std::move(cl)); | |
151 | } | |
152 | { | |
153 | DerivedFromTestClass cl(42); | |
154 | test_b12<int&(NonCopyable&&) &, int&>(cl); | |
155 | test_b12<int const&(NonCopyable&&) const &, int const&>(cl); | |
156 | test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(cl); | |
157 | test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(cl); | |
158 | ||
159 | test_b12<int&&(NonCopyable&&) &&, int&&>(std::move(cl)); | |
160 | test_b12<int const&&(NonCopyable&&) const &&, int const&&>(std::move(cl)); | |
161 | test_b12<int volatile&&(NonCopyable&&) volatile &&, int volatile&&>(std::move(cl)); | |
162 | test_b12<int const volatile&&(NonCopyable&&) const volatile &&, int const volatile&&>(std::move(cl)); | |
163 | } | |
164 | { | |
165 | TestClass cl_obj(42); | |
166 | TestClass *cl = &cl_obj; | |
167 | test_b12<int&(NonCopyable&&) &, int&>(cl); | |
168 | test_b12<int const&(NonCopyable&&) const &, int const&>(cl); | |
169 | test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(cl); | |
170 | test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(cl); | |
171 | } | |
172 | { | |
173 | DerivedFromTestClass cl_obj(42); | |
174 | DerivedFromTestClass *cl = &cl_obj; | |
175 | test_b12<int&(NonCopyable&&) &, int&>(cl); | |
176 | test_b12<int const&(NonCopyable&&) const &, int const&>(cl); | |
177 | test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(cl); | |
178 | test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(cl); | |
179 | } | |
180 | ||
181 | // Bullets 3 & 4 in the standard | |
182 | { | |
183 | using Fn = TestClass; | |
184 | Fn cl(42); | |
185 | test_b34<int&>(cl); | |
186 | test_b34<int const&>(static_cast<Fn const&>(cl)); | |
187 | test_b34<int volatile&>(static_cast<Fn volatile&>(cl)); | |
188 | test_b34<int const volatile&>(static_cast<Fn const volatile &>(cl)); | |
189 | ||
190 | test_b34<int&&>(static_cast<Fn &&>(cl)); | |
191 | test_b34<int const&&>(static_cast<Fn const&&>(cl)); | |
192 | test_b34<int volatile&&>(static_cast<Fn volatile&&>(cl)); | |
193 | test_b34<int const volatile&&>(static_cast<Fn const volatile&&>(cl)); | |
194 | } | |
195 | { | |
196 | using Fn = DerivedFromTestClass; | |
197 | Fn cl(42); | |
198 | test_b34<int&>(cl); | |
199 | test_b34<int const&>(static_cast<Fn const&>(cl)); | |
200 | test_b34<int volatile&>(static_cast<Fn volatile&>(cl)); | |
201 | test_b34<int const volatile&>(static_cast<Fn const volatile &>(cl)); | |
202 | ||
203 | test_b34<int&&>(static_cast<Fn &&>(cl)); | |
204 | test_b34<int const&&>(static_cast<Fn const&&>(cl)); | |
205 | test_b34<int volatile&&>(static_cast<Fn volatile&&>(cl)); | |
206 | test_b34<int const volatile&&>(static_cast<Fn const volatile&&>(cl)); | |
207 | } | |
208 | { | |
209 | using Fn = TestClass; | |
210 | Fn cl_obj(42); | |
211 | Fn* cl = &cl_obj; | |
212 | test_b34<int&>(cl); | |
213 | test_b34<int const&>(static_cast<Fn const*>(cl)); | |
214 | test_b34<int volatile&>(static_cast<Fn volatile*>(cl)); | |
215 | test_b34<int const volatile&>(static_cast<Fn const volatile *>(cl)); | |
216 | } | |
217 | { | |
218 | using Fn = DerivedFromTestClass; | |
219 | Fn cl_obj(42); | |
220 | Fn* cl = &cl_obj; | |
221 | test_b34<int&>(cl); | |
222 | test_b34<int const&>(static_cast<Fn const*>(cl)); | |
223 | test_b34<int volatile&>(static_cast<Fn volatile*>(cl)); | |
224 | test_b34<int const volatile&>(static_cast<Fn const volatile *>(cl)); | |
225 | } | |
226 | ||
227 | // Bullet 5 in the standard | |
228 | using FooType = int&(NonCopyable&&); | |
229 | { | |
230 | FooType& fn = foo; | |
231 | test_b5<int &>(fn); | |
232 | } | |
233 | { | |
234 | FooType* fn = foo; | |
235 | test_b5<int &>(fn); | |
236 | } | |
237 | { | |
238 | using Fn = TestClass; | |
239 | Fn cl(42); | |
240 | test_b5<int&>(cl); | |
241 | test_b5<int const&>(static_cast<Fn const&>(cl)); | |
242 | test_b5<int volatile&>(static_cast<Fn volatile&>(cl)); | |
243 | test_b5<int const volatile&>(static_cast<Fn const volatile &>(cl)); | |
244 | ||
245 | test_b5<int&&>(static_cast<Fn &&>(cl)); | |
246 | test_b5<int const&&>(static_cast<Fn const&&>(cl)); | |
247 | test_b5<int volatile&&>(static_cast<Fn volatile&&>(cl)); | |
248 | test_b5<int const volatile&&>(static_cast<Fn const volatile&&>(cl)); | |
249 | } | |
250 | } |