]>
Commit | Line | Data |
---|---|---|
1 | // Copyright Louis Dionne 2013-2016 | |
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 | ||
66 | // Check that result_of_t matches Expect. | |
67 | using ResultOfReturnType = typename std::result_of<ClassFunc&&(Functor&&, NonCopyable&&)>::type; | |
68 | static_assert(std::is_same<ResultOfReturnType, Expect>::value, ""); | |
69 | ||
70 | // Run invoke and check the return value. | |
71 | DeducedReturnType ret = hana::apply(func_ptr, std::forward<Functor>(f), std::move(arg)); | |
72 | BOOST_HANA_RUNTIME_CHECK(ret == 42); | |
73 | } | |
74 | ||
75 | template <typename Expect, typename Functor> | |
76 | void test_b34(Functor&& f) { | |
77 | // Create the callable object. | |
78 | using ClassFunc = int TestClass::*; | |
79 | ClassFunc func_ptr = &TestClass::data; | |
80 | ||
81 | // Check that the deduced return type of invoke is what is expected. | |
82 | using DeducedReturnType = decltype( | |
83 | hana::apply(func_ptr, std::forward<Functor>(f)) | |
84 | ); | |
85 | static_assert(std::is_same<DeducedReturnType, Expect>::value, ""); | |
86 | ||
87 | // Check that result_of_t matches Expect. | |
88 | using ResultOfReturnType = typename std::result_of<ClassFunc&&(Functor&&)>::type; | |
89 | static_assert(std::is_same<ResultOfReturnType, Expect>::value, ""); | |
90 | ||
91 | // Run invoke and check the return value. | |
92 | DeducedReturnType ret = hana::apply(func_ptr, std::forward<Functor>(f)); | |
93 | BOOST_HANA_RUNTIME_CHECK(ret == 42); | |
94 | } | |
95 | ||
96 | template <typename Expect, typename Functor> | |
97 | void test_b5(Functor&& f) { | |
98 | NonCopyable arg; | |
99 | ||
100 | // Check that the deduced return type of invoke is what is expected. | |
101 | using DeducedReturnType = decltype( | |
102 | hana::apply(std::forward<Functor>(f), std::move(arg)) | |
103 | ); | |
104 | static_assert(std::is_same<DeducedReturnType, Expect>::value, ""); | |
105 | ||
106 | // Check that result_of_t matches Expect. | |
107 | using ResultOfReturnType = typename std::result_of<Functor&&(NonCopyable&&)>::type; | |
108 | static_assert(std::is_same<ResultOfReturnType, Expect>::value, ""); | |
109 | ||
110 | // Run invoke and check the return value. | |
111 | DeducedReturnType ret = hana::apply(std::forward<Functor>(f), std::move(arg)); | |
112 | BOOST_HANA_RUNTIME_CHECK(ret == 42); | |
113 | } | |
114 | ||
115 | int& foo(NonCopyable&&) { | |
116 | static int data = 42; | |
117 | return data; | |
118 | } | |
119 | ||
120 | int main() { | |
121 | // Test normal usage with a function object | |
122 | { | |
123 | hana::test::_injection<0> f{}; | |
124 | using hana::test::ct_eq; | |
125 | ||
126 | BOOST_HANA_CONSTANT_CHECK(hana::equal( | |
127 | hana::apply(f), | |
128 | f() | |
129 | )); | |
130 | BOOST_HANA_CONSTANT_CHECK(hana::equal( | |
131 | hana::apply(f, ct_eq<0>{}), | |
132 | f(ct_eq<0>{}) | |
133 | )); | |
134 | BOOST_HANA_CONSTANT_CHECK(hana::equal( | |
135 | hana::apply(f, ct_eq<0>{}, ct_eq<1>{}), | |
136 | f(ct_eq<0>{}, ct_eq<1>{}) | |
137 | )); | |
138 | BOOST_HANA_CONSTANT_CHECK(hana::equal( | |
139 | hana::apply(f, ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}), | |
140 | f(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}) | |
141 | )); | |
142 | BOOST_HANA_CONSTANT_CHECK(hana::equal( | |
143 | hana::apply(f, ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{}), | |
144 | f(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{}) | |
145 | )); | |
146 | ||
147 | // Make sure we can use apply with non-PODs | |
148 | hana::apply(f, nonpod<>{}); | |
149 | } | |
150 | ||
151 | // Bullets 1 & 2 in the standard | |
152 | { | |
153 | TestClass 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 | DerivedFromTestClass cl(42); | |
166 | test_b12<int&(NonCopyable&&) &, int&>(cl); | |
167 | test_b12<int const&(NonCopyable&&) const &, int const&>(cl); | |
168 | test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(cl); | |
169 | test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(cl); | |
170 | ||
171 | test_b12<int&&(NonCopyable&&) &&, int&&>(std::move(cl)); | |
172 | test_b12<int const&&(NonCopyable&&) const &&, int const&&>(std::move(cl)); | |
173 | test_b12<int volatile&&(NonCopyable&&) volatile &&, int volatile&&>(std::move(cl)); | |
174 | test_b12<int const volatile&&(NonCopyable&&) const volatile &&, int const volatile&&>(std::move(cl)); | |
175 | } | |
176 | { | |
177 | TestClass cl_obj(42); | |
178 | TestClass *cl = &cl_obj; | |
179 | test_b12<int&(NonCopyable&&) &, int&>(cl); | |
180 | test_b12<int const&(NonCopyable&&) const &, int const&>(cl); | |
181 | test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(cl); | |
182 | test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(cl); | |
183 | } | |
184 | { | |
185 | DerivedFromTestClass cl_obj(42); | |
186 | DerivedFromTestClass *cl = &cl_obj; | |
187 | test_b12<int&(NonCopyable&&) &, int&>(cl); | |
188 | test_b12<int const&(NonCopyable&&) const &, int const&>(cl); | |
189 | test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(cl); | |
190 | test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(cl); | |
191 | } | |
192 | ||
193 | // Bullets 3 & 4 in the standard | |
194 | { | |
195 | using Fn = TestClass; | |
196 | Fn cl(42); | |
197 | test_b34<int&>(cl); | |
198 | test_b34<int const&>(static_cast<Fn const&>(cl)); | |
199 | test_b34<int volatile&>(static_cast<Fn volatile&>(cl)); | |
200 | test_b34<int const volatile&>(static_cast<Fn const volatile &>(cl)); | |
201 | ||
202 | test_b34<int&&>(static_cast<Fn &&>(cl)); | |
203 | test_b34<int const&&>(static_cast<Fn const&&>(cl)); | |
204 | test_b34<int volatile&&>(static_cast<Fn volatile&&>(cl)); | |
205 | test_b34<int const volatile&&>(static_cast<Fn const volatile&&>(cl)); | |
206 | } | |
207 | { | |
208 | using Fn = DerivedFromTestClass; | |
209 | Fn cl(42); | |
210 | test_b34<int&>(cl); | |
211 | test_b34<int const&>(static_cast<Fn const&>(cl)); | |
212 | test_b34<int volatile&>(static_cast<Fn volatile&>(cl)); | |
213 | test_b34<int const volatile&>(static_cast<Fn const volatile &>(cl)); | |
214 | ||
215 | test_b34<int&&>(static_cast<Fn &&>(cl)); | |
216 | test_b34<int const&&>(static_cast<Fn const&&>(cl)); | |
217 | test_b34<int volatile&&>(static_cast<Fn volatile&&>(cl)); | |
218 | test_b34<int const volatile&&>(static_cast<Fn const volatile&&>(cl)); | |
219 | } | |
220 | { | |
221 | using Fn = TestClass; | |
222 | Fn cl_obj(42); | |
223 | Fn* cl = &cl_obj; | |
224 | test_b34<int&>(cl); | |
225 | test_b34<int const&>(static_cast<Fn const*>(cl)); | |
226 | test_b34<int volatile&>(static_cast<Fn volatile*>(cl)); | |
227 | test_b34<int const volatile&>(static_cast<Fn const volatile *>(cl)); | |
228 | } | |
229 | { | |
230 | using Fn = DerivedFromTestClass; | |
231 | Fn cl_obj(42); | |
232 | Fn* cl = &cl_obj; | |
233 | test_b34<int&>(cl); | |
234 | test_b34<int const&>(static_cast<Fn const*>(cl)); | |
235 | test_b34<int volatile&>(static_cast<Fn volatile*>(cl)); | |
236 | test_b34<int const volatile&>(static_cast<Fn const volatile *>(cl)); | |
237 | } | |
238 | ||
239 | // Bullet 5 in the standard | |
240 | using FooType = int&(NonCopyable&&); | |
241 | { | |
242 | FooType& fn = foo; | |
243 | test_b5<int &>(fn); | |
244 | } | |
245 | { | |
246 | FooType* fn = foo; | |
247 | test_b5<int &>(fn); | |
248 | } | |
249 | { | |
250 | using Fn = TestClass; | |
251 | Fn cl(42); | |
252 | test_b5<int&>(cl); | |
253 | test_b5<int const&>(static_cast<Fn const&>(cl)); | |
254 | test_b5<int volatile&>(static_cast<Fn volatile&>(cl)); | |
255 | test_b5<int const volatile&>(static_cast<Fn const volatile &>(cl)); | |
256 | ||
257 | test_b5<int&&>(static_cast<Fn &&>(cl)); | |
258 | test_b5<int const&&>(static_cast<Fn const&&>(cl)); | |
259 | test_b5<int volatile&&>(static_cast<Fn volatile&&>(cl)); | |
260 | test_b5<int const volatile&&>(static_cast<Fn const volatile&&>(cl)); | |
261 | } | |
262 | } |