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 | // <functional> |
12 | |
13 | // ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_CXX20_REMOVED_TYPE_TRAITS |
14 | // ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS |
15 | |
16 | // template<class F, class... Args> |
17 | // invoke_result_t<F, Args...> invoke(F&& f, Args&&... args) // C++17 |
18 | // noexcept(is_nothrow_invocable_v<_Fn, _Args...>); |
19 | |
20 | /// C++14 [func.def] 20.9.0 |
21 | /// (1) The following definitions apply to this Clause: |
22 | /// (2) A call signature is the name of a return type followed by a parenthesized |
23 | /// comma-separated list of zero or more argument types. |
24 | /// (3) A callable type is a function object type (20.9) or a pointer to member. |
25 | /// (4) A callable object is an object of a callable type. |
26 | /// (5) A call wrapper type is a type that holds a callable object and supports |
27 | /// a call operation that forwards to that object. |
28 | /// (6) A call wrapper is an object of a call wrapper type. |
29 | /// (7) A target object is the callable object held by a call wrapper. |
30 | |
31 | /// C++14 [func.require] 20.9.1 |
32 | /// |
33 | /// Define INVOKE (f, t1, t2, ..., tN) as follows: |
34 | /// (1.1) - (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is an object of |
35 | /// type T or a reference to an object of type T or a reference to an object of a type derived from T; |
36 | /// (1.2) - ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is not one of |
37 | /// the types described in the previous item; |
38 | /// (1.3) - t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is an object of type T or a |
39 | /// reference to an object of type T or a reference to an object of a type derived from T; |
40 | /// (1.4) - (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1 is not one of the types |
41 | /// described in the previous item; |
42 | /// (1.5) - f(t1, t2, ..., tN) in all other cases. |
43 | |
44 | #include <functional> |
45 | #include <type_traits> |
46 | #include <utility> // for std::move |
47 | #include <cassert> |
48 | |
49 | #include "test_macros.h" |
50 | |
51 | struct NonCopyable { |
52 | NonCopyable() {} |
53 | private: |
54 | NonCopyable(NonCopyable const&) = delete; |
55 | NonCopyable& operator=(NonCopyable const&) = delete; |
56 | }; |
57 | |
58 | struct TestClass { |
59 | explicit TestClass(int x) : data(x) {} |
60 | |
61 | int& operator()(NonCopyable&&) & { return data; } |
62 | int const& operator()(NonCopyable&&) const & { return data; } |
63 | int volatile& operator()(NonCopyable&&) volatile & { return data; } |
64 | int const volatile& operator()(NonCopyable&&) const volatile & { return data; } |
65 | |
66 | int&& operator()(NonCopyable&&) && { return std::move(data); } |
67 | int const&& operator()(NonCopyable&&) const && { return std::move(data); } |
68 | int volatile&& operator()(NonCopyable&&) volatile && { return std::move(data); } |
69 | int const volatile&& operator()(NonCopyable&&) const volatile && { return std::move(data); } |
70 | |
71 | int data; |
72 | private: |
73 | TestClass(TestClass const&) = delete; |
74 | TestClass& operator=(TestClass const&) = delete; |
75 | }; |
76 | |
77 | struct DerivedFromTestClass : public TestClass { |
78 | explicit DerivedFromTestClass(int x) : TestClass(x) {} |
79 | }; |
80 | |
81 | int& foo(NonCopyable&&) { |
82 | static int data = 42; |
83 | return data; |
84 | } |
85 | |
86 | template <class Signature, class Expect, class Functor> |
87 | void test_b12(Functor&& f) { |
88 | // Create the callable object. |
89 | typedef Signature TestClass::*ClassFunc; |
90 | ClassFunc func_ptr = &TestClass::operator(); |
91 | |
92 | // Create the dummy arg. |
93 | NonCopyable arg; |
94 | |
95 | // Check that the deduced return type of invoke is what is expected. |
96 | typedef decltype( |
97 | std::invoke(func_ptr, std::forward<Functor>(f), std::move(arg)) |
98 | ) DeducedReturnType; |
99 | static_assert((std::is_same<DeducedReturnType, Expect>::value), "" ); |
100 | |
101 | // Check that result_of_t matches Expect. |
102 | typedef typename std::result_of<ClassFunc&&(Functor&&, NonCopyable&&)>::type |
103 | ResultOfReturnType; |
104 | static_assert((std::is_same<ResultOfReturnType, Expect>::value), "" ); |
105 | |
106 | // Run invoke and check the return value. |
107 | DeducedReturnType ret = |
108 | std::invoke(func_ptr, std::forward<Functor>(f), std::move(arg)); |
109 | assert(ret == 42); |
110 | } |
111 | |
112 | template <class Expect, class Functor> |
113 | void test_b34(Functor&& f) { |
114 | // Create the callable object. |
115 | typedef int TestClass::*ClassFunc; |
116 | ClassFunc func_ptr = &TestClass::data; |
117 | |
118 | // Check that the deduced return type of invoke is what is expected. |
119 | typedef decltype( |
120 | std::invoke(func_ptr, std::forward<Functor>(f)) |
121 | ) DeducedReturnType; |
122 | static_assert((std::is_same<DeducedReturnType, Expect>::value), "" ); |
123 | |
124 | // Check that result_of_t matches Expect. |
125 | typedef typename std::result_of<ClassFunc&&(Functor&&)>::type |
126 | ResultOfReturnType; |
127 | static_assert((std::is_same<ResultOfReturnType, Expect>::value), "" ); |
128 | |
129 | // Run invoke and check the return value. |
130 | DeducedReturnType ret = |
131 | std::invoke(func_ptr, std::forward<Functor>(f)); |
132 | assert(ret == 42); |
133 | } |
134 | |
135 | template <class Expect, class Functor> |
136 | void test_b5(Functor&& f) { |
137 | NonCopyable arg; |
138 | |
139 | // Check that the deduced return type of invoke is what is expected. |
140 | typedef decltype( |
141 | std::invoke(std::forward<Functor>(f), std::move(arg)) |
142 | ) DeducedReturnType; |
143 | static_assert((std::is_same<DeducedReturnType, Expect>::value), "" ); |
144 | |
145 | // Check that result_of_t matches Expect. |
146 | typedef typename std::result_of<Functor&&(NonCopyable&&)>::type |
147 | ResultOfReturnType; |
148 | static_assert((std::is_same<ResultOfReturnType, Expect>::value), "" ); |
149 | |
150 | // Run invoke and check the return value. |
151 | DeducedReturnType ret = std::invoke(std::forward<Functor>(f), std::move(arg)); |
152 | assert(ret == 42); |
153 | } |
154 | |
155 | void bullet_one_two_tests() { |
156 | { |
157 | TestClass cl(42); |
158 | test_b12<int&(NonCopyable&&) &, int&>(f&: cl); |
159 | test_b12<int const&(NonCopyable&&) const &, int const&>(f&: cl); |
160 | test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(f&: cl); |
161 | test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(f&: cl); |
162 | |
163 | test_b12<int&&(NonCopyable&&) &&, int&&>(f: std::move(cl)); |
164 | test_b12<int const&&(NonCopyable&&) const &&, int const&&>(f: std::move(cl)); |
165 | test_b12<int volatile&&(NonCopyable&&) volatile &&, int volatile&&>(f: std::move(cl)); |
166 | test_b12<int const volatile&&(NonCopyable&&) const volatile &&, int const volatile&&>(f: std::move(cl)); |
167 | } |
168 | { |
169 | DerivedFromTestClass cl(42); |
170 | test_b12<int&(NonCopyable&&) &, int&>(f&: cl); |
171 | test_b12<int const&(NonCopyable&&) const &, int const&>(f&: cl); |
172 | test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(f&: cl); |
173 | test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(f&: cl); |
174 | |
175 | test_b12<int&&(NonCopyable&&) &&, int&&>(f: std::move(cl)); |
176 | test_b12<int const&&(NonCopyable&&) const &&, int const&&>(f: std::move(cl)); |
177 | test_b12<int volatile&&(NonCopyable&&) volatile &&, int volatile&&>(f: std::move(cl)); |
178 | test_b12<int const volatile&&(NonCopyable&&) const volatile &&, int const volatile&&>(f: std::move(cl)); |
179 | } |
180 | { |
181 | TestClass cl_obj(42); |
182 | std::reference_wrapper<TestClass> cl(cl_obj); |
183 | test_b12<int&(NonCopyable&&) &, int&>(f&: cl); |
184 | test_b12<int const&(NonCopyable&&) const &, int const&>(f&: cl); |
185 | test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(f&: cl); |
186 | test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(f&: cl); |
187 | |
188 | test_b12<int&(NonCopyable&&) &, int&>(f: std::move(cl)); |
189 | test_b12<int const&(NonCopyable&&) const &, int const&>(f: std::move(cl)); |
190 | test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(f: std::move(cl)); |
191 | test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(f: std::move(cl)); |
192 | } |
193 | { |
194 | DerivedFromTestClass cl_obj(42); |
195 | std::reference_wrapper<DerivedFromTestClass> cl(cl_obj); |
196 | test_b12<int&(NonCopyable&&) &, int&>(f&: cl); |
197 | test_b12<int const&(NonCopyable&&) const &, int const&>(f&: cl); |
198 | test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(f&: cl); |
199 | test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(f&: cl); |
200 | |
201 | test_b12<int&(NonCopyable&&) &, int&>(f: std::move(cl)); |
202 | test_b12<int const&(NonCopyable&&) const &, int const&>(f: std::move(cl)); |
203 | test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(f: std::move(cl)); |
204 | test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(f: std::move(cl)); |
205 | } |
206 | { |
207 | TestClass cl_obj(42); |
208 | TestClass *cl = &cl_obj; |
209 | test_b12<int&(NonCopyable&&) &, int&>(f&: cl); |
210 | test_b12<int const&(NonCopyable&&) const &, int const&>(f&: cl); |
211 | test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(f&: cl); |
212 | test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(f&: cl); |
213 | } |
214 | { |
215 | DerivedFromTestClass cl_obj(42); |
216 | DerivedFromTestClass *cl = &cl_obj; |
217 | test_b12<int&(NonCopyable&&) &, int&>(f&: cl); |
218 | test_b12<int const&(NonCopyable&&) const &, int const&>(f&: cl); |
219 | test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(f&: cl); |
220 | test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(f&: cl); |
221 | } |
222 | } |
223 | |
224 | void bullet_three_four_tests() { |
225 | { |
226 | typedef TestClass Fn; |
227 | Fn cl(42); |
228 | test_b34<int&>(f&: cl); |
229 | test_b34<int const&>(f: static_cast<Fn const&>(cl)); |
230 | test_b34<int volatile&>(f&: static_cast<Fn volatile&>(cl)); |
231 | test_b34<int const volatile&>(f: static_cast<Fn const volatile &>(cl)); |
232 | |
233 | test_b34<int&&>(f: static_cast<Fn &&>(cl)); |
234 | test_b34<int const&&>(f: static_cast<Fn const&&>(cl)); |
235 | test_b34<int volatile&&>(f: static_cast<Fn volatile&&>(cl)); |
236 | test_b34<int const volatile&&>(f: static_cast<Fn const volatile&&>(cl)); |
237 | } |
238 | { |
239 | typedef DerivedFromTestClass Fn; |
240 | Fn cl(42); |
241 | test_b34<int&>(f&: cl); |
242 | test_b34<int const&>(f: static_cast<Fn const&>(cl)); |
243 | test_b34<int volatile&>(f&: static_cast<Fn volatile&>(cl)); |
244 | test_b34<int const volatile&>(f: static_cast<Fn const volatile &>(cl)); |
245 | |
246 | test_b34<int&&>(f: static_cast<Fn &&>(cl)); |
247 | test_b34<int const&&>(f: static_cast<Fn const&&>(cl)); |
248 | test_b34<int volatile&&>(f: static_cast<Fn volatile&&>(cl)); |
249 | test_b34<int const volatile&&>(f: static_cast<Fn const volatile&&>(cl)); |
250 | } |
251 | { |
252 | typedef TestClass Fn; |
253 | Fn cl(42); |
254 | test_b34<int&>(f: std::reference_wrapper<Fn>(cl)); |
255 | test_b34<int const&>(f: std::reference_wrapper<Fn const>(cl)); |
256 | test_b34<int volatile&>(f: std::reference_wrapper<Fn volatile>(cl)); |
257 | test_b34<int const volatile&>(f: std::reference_wrapper<Fn const volatile>(cl)); |
258 | } |
259 | { |
260 | typedef DerivedFromTestClass Fn; |
261 | Fn cl(42); |
262 | test_b34<int&>(f: std::reference_wrapper<Fn>(cl)); |
263 | test_b34<int const&>(f: std::reference_wrapper<Fn const>(cl)); |
264 | test_b34<int volatile&>(f: std::reference_wrapper<Fn volatile>(cl)); |
265 | test_b34<int const volatile&>(f: std::reference_wrapper<Fn const volatile>(cl)); |
266 | } |
267 | { |
268 | typedef TestClass Fn; |
269 | Fn cl_obj(42); |
270 | Fn* cl = &cl_obj; |
271 | test_b34<int&>(f&: cl); |
272 | test_b34<int const&>(f: static_cast<Fn const*>(cl)); |
273 | test_b34<int volatile&>(f: static_cast<Fn volatile*>(cl)); |
274 | test_b34<int const volatile&>(f: static_cast<Fn const volatile *>(cl)); |
275 | } |
276 | { |
277 | typedef DerivedFromTestClass Fn; |
278 | Fn cl_obj(42); |
279 | Fn* cl = &cl_obj; |
280 | test_b34<int&>(f&: cl); |
281 | test_b34<int const&>(f: static_cast<Fn const*>(cl)); |
282 | test_b34<int volatile&>(f: static_cast<Fn volatile*>(cl)); |
283 | test_b34<int const volatile&>(f: static_cast<Fn const volatile *>(cl)); |
284 | } |
285 | } |
286 | |
287 | void bullet_five_tests() { |
288 | using = int&(NonCopyable&&); |
289 | { |
290 | FooType& fn = foo; |
291 | test_b5<int &>(f&: fn); |
292 | } |
293 | { |
294 | FooType* fn = foo; |
295 | test_b5<int &>(f&: fn); |
296 | } |
297 | { |
298 | typedef TestClass Fn; |
299 | Fn cl(42); |
300 | test_b5<int&>(f&: cl); |
301 | test_b5<int const&>(f: static_cast<Fn const&>(cl)); |
302 | test_b5<int volatile&>(f&: static_cast<Fn volatile&>(cl)); |
303 | test_b5<int const volatile&>(f: static_cast<Fn const volatile &>(cl)); |
304 | |
305 | test_b5<int&&>(f: static_cast<Fn &&>(cl)); |
306 | test_b5<int const&&>(f: static_cast<Fn const&&>(cl)); |
307 | test_b5<int volatile&&>(f: static_cast<Fn volatile&&>(cl)); |
308 | test_b5<int const volatile&&>(f: static_cast<Fn const volatile&&>(cl)); |
309 | } |
310 | } |
311 | |
312 | struct CopyThrows { |
313 | CopyThrows() {} |
314 | CopyThrows(CopyThrows const&) {} |
315 | CopyThrows(CopyThrows&&) noexcept {} |
316 | }; |
317 | |
318 | struct NoThrowCallable { |
319 | void operator()() noexcept {} |
320 | void operator()(CopyThrows) noexcept {} |
321 | }; |
322 | |
323 | struct ThrowsCallable { |
324 | void operator()() {} |
325 | }; |
326 | |
327 | struct MemberObj { |
328 | int x; |
329 | }; |
330 | |
331 | void noexcept_test() { |
332 | { |
333 | NoThrowCallable obj; ((void)obj); // suppress unused warning |
334 | CopyThrows arg; ((void)arg); // suppress unused warning |
335 | static_assert(noexcept(std::invoke(fn&: obj)), "" ); |
336 | static_assert(!noexcept(std::invoke(fn&: obj, args&: arg)), "" ); |
337 | static_assert(noexcept(std::invoke(fn&: obj, args: std::move(arg))), "" ); |
338 | } |
339 | { |
340 | ThrowsCallable obj; ((void)obj); // suppress unused warning |
341 | static_assert(!noexcept(std::invoke(fn&: obj)), "" ); |
342 | } |
343 | { |
344 | MemberObj obj{.x: 42}; ((void)obj); // suppress unused warning. |
345 | static_assert(noexcept(std::invoke(fn: &MemberObj::x, args&: obj)), "" ); |
346 | } |
347 | } |
348 | |
349 | // LWG3655: The INVOKE operation and union types |
350 | void union_tests() { |
351 | union Union { |
352 | int x; |
353 | int f() { return 42; } |
354 | int g() const { return 52; } |
355 | }; |
356 | |
357 | // With a data member |
358 | { |
359 | auto get = []() -> Union { return Union{.x = 3}; }; |
360 | int result = std::invoke(fn: &Union::x, args: get()); |
361 | assert(result == 3); |
362 | } |
363 | { |
364 | auto get = []() -> Union const { return Union{.x = 3}; }; |
365 | int result = std::invoke(fn: &Union::x, args: get()); |
366 | assert(result == 3); |
367 | } |
368 | { |
369 | Union u{.x: 3}; |
370 | int& result = std::invoke(fn: &Union::x, args&: u); |
371 | assert(&result == &u.x); |
372 | } |
373 | { |
374 | Union const u{.x: 3}; |
375 | int const& result = std::invoke(fn: &Union::x, args: u); |
376 | assert(&result == &u.x); |
377 | } |
378 | |
379 | // With a pointer to a member function |
380 | { |
381 | auto get = []() -> Union { return Union{.x = 3}; }; |
382 | int result = std::invoke(&Union::f, get()); |
383 | assert(result == 42); |
384 | } |
385 | { |
386 | Union u{.x: 3}; |
387 | int result = std::invoke(&Union::f, u); |
388 | assert(result == 42); |
389 | } |
390 | { |
391 | // constness mismatch |
392 | static_assert(!std::is_invocable_v<int (Union::*)(), Union const>); |
393 | static_assert(!std::is_invocable_v<int (Union::*)(), Union const&>); |
394 | } |
395 | |
396 | { |
397 | auto get = []() -> Union { return Union{.x = 3}; }; |
398 | int result = std::invoke(&Union::g, get()); |
399 | assert(result == 52); |
400 | } |
401 | { |
402 | auto get = []() -> Union const { return Union{.x = 3}; }; |
403 | int result = std::invoke(&Union::g, get()); |
404 | assert(result == 52); |
405 | } |
406 | { |
407 | Union u{.x: 3}; |
408 | int result = std::invoke(&Union::g, u); |
409 | assert(result == 52); |
410 | } |
411 | { |
412 | Union const u{.x: 3}; |
413 | int result = std::invoke(&Union::g, u); |
414 | assert(result == 52); |
415 | } |
416 | } |
417 | |
418 | int main(int, char**) { |
419 | bullet_one_two_tests(); |
420 | bullet_three_four_tests(); |
421 | bullet_five_tests(); |
422 | noexcept_test(); |
423 | |
424 | return 0; |
425 | } |
426 | |