xref: /llvm-project/libcxx/test/std/utilities/function.objects/func.invoke/invoke.pass.cpp (revision 910b76a002713414a7249a7ac8eef52aa8eab748)
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 {
NonCopyableNonCopyable52     NonCopyable() {}
53 private:
54     NonCopyable(NonCopyable const&) = delete;
55     NonCopyable& operator=(NonCopyable const&) = delete;
56 };
57 
58 struct TestClass {
TestClassTestClass59     explicit TestClass(int x) : data(x) {}
60 
operator ()TestClass61     int& operator()(NonCopyable&&) & { return data; }
operator ()TestClass62     int const& operator()(NonCopyable&&) const & { return data; }
operator ()TestClass63     int volatile& operator()(NonCopyable&&) volatile & { return data; }
operator ()TestClass64     int const volatile& operator()(NonCopyable&&) const volatile & { return data; }
65 
operator ()TestClass66     int&& operator()(NonCopyable&&) && { return std::move(data); }
operator ()TestClass67     int const&& operator()(NonCopyable&&) const && { return std::move(data); }
operator ()TestClass68     int volatile&& operator()(NonCopyable&&) volatile && { return std::move(data); }
operator ()TestClass69     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 {
DerivedFromTestClassDerivedFromTestClass78     explicit DerivedFromTestClass(int x) : TestClass(x) {}
79 };
80 
foo(NonCopyable &&)81 int& foo(NonCopyable&&) {
82     static int data = 42;
83     return data;
84 }
85 
86 template <class Signature,  class Expect, class Functor>
test_b12(Functor && f)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>
test_b34(Functor && f)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>
test_b5(Functor && f)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 
bullet_one_two_tests()155 void bullet_one_two_tests() {
156     {
157         TestClass cl(42);
158         test_b12<int&(NonCopyable&&) &, int&>(cl);
159         test_b12<int const&(NonCopyable&&) const &, int const&>(cl);
160         test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(cl);
161         test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(cl);
162 
163         test_b12<int&&(NonCopyable&&) &&, int&&>(std::move(cl));
164         test_b12<int const&&(NonCopyable&&) const &&, int const&&>(std::move(cl));
165         test_b12<int volatile&&(NonCopyable&&) volatile &&, int volatile&&>(std::move(cl));
166         test_b12<int const volatile&&(NonCopyable&&) const volatile &&, int const volatile&&>(std::move(cl));
167     }
168     {
169         DerivedFromTestClass cl(42);
170         test_b12<int&(NonCopyable&&) &, int&>(cl);
171         test_b12<int const&(NonCopyable&&) const &, int const&>(cl);
172         test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(cl);
173         test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(cl);
174 
175         test_b12<int&&(NonCopyable&&) &&, int&&>(std::move(cl));
176         test_b12<int const&&(NonCopyable&&) const &&, int const&&>(std::move(cl));
177         test_b12<int volatile&&(NonCopyable&&) volatile &&, int volatile&&>(std::move(cl));
178         test_b12<int const volatile&&(NonCopyable&&) const volatile &&, int const volatile&&>(std::move(cl));
179     }
180     {
181         TestClass cl_obj(42);
182         std::reference_wrapper<TestClass> cl(cl_obj);
183         test_b12<int&(NonCopyable&&) &, int&>(cl);
184         test_b12<int const&(NonCopyable&&) const &, int const&>(cl);
185         test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(cl);
186         test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(cl);
187 
188         test_b12<int&(NonCopyable&&) &, int&>(std::move(cl));
189         test_b12<int const&(NonCopyable&&) const &, int const&>(std::move(cl));
190         test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(std::move(cl));
191         test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(std::move(cl));
192     }
193     {
194         DerivedFromTestClass cl_obj(42);
195         std::reference_wrapper<DerivedFromTestClass> cl(cl_obj);
196         test_b12<int&(NonCopyable&&) &, int&>(cl);
197         test_b12<int const&(NonCopyable&&) const &, int const&>(cl);
198         test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(cl);
199         test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(cl);
200 
201         test_b12<int&(NonCopyable&&) &, int&>(std::move(cl));
202         test_b12<int const&(NonCopyable&&) const &, int const&>(std::move(cl));
203         test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(std::move(cl));
204         test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(std::move(cl));
205     }
206     {
207         TestClass cl_obj(42);
208         TestClass *cl = &cl_obj;
209         test_b12<int&(NonCopyable&&) &, int&>(cl);
210         test_b12<int const&(NonCopyable&&) const &, int const&>(cl);
211         test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(cl);
212         test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(cl);
213     }
214     {
215         DerivedFromTestClass cl_obj(42);
216         DerivedFromTestClass *cl = &cl_obj;
217         test_b12<int&(NonCopyable&&) &, int&>(cl);
218         test_b12<int const&(NonCopyable&&) const &, int const&>(cl);
219         test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(cl);
220         test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(cl);
221     }
222 }
223 
bullet_three_four_tests()224 void bullet_three_four_tests() {
225     {
226         typedef TestClass Fn;
227         Fn cl(42);
228         test_b34<int&>(cl);
229         test_b34<int const&>(static_cast<Fn const&>(cl));
230         test_b34<int volatile&>(static_cast<Fn volatile&>(cl));
231         test_b34<int const volatile&>(static_cast<Fn const volatile &>(cl));
232 
233         test_b34<int&&>(static_cast<Fn &&>(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         typedef DerivedFromTestClass Fn;
240         Fn cl(42);
241         test_b34<int&>(cl);
242         test_b34<int const&>(static_cast<Fn const&>(cl));
243         test_b34<int volatile&>(static_cast<Fn volatile&>(cl));
244         test_b34<int const volatile&>(static_cast<Fn const volatile &>(cl));
245 
246         test_b34<int&&>(static_cast<Fn &&>(cl));
247         test_b34<int const&&>(static_cast<Fn const&&>(cl));
248         test_b34<int volatile&&>(static_cast<Fn volatile&&>(cl));
249         test_b34<int const volatile&&>(static_cast<Fn const volatile&&>(cl));
250     }
251     {
252         typedef TestClass Fn;
253         Fn cl(42);
254         test_b34<int&>(std::reference_wrapper<Fn>(cl));
255         test_b34<int const&>(std::reference_wrapper<Fn const>(cl));
256         test_b34<int volatile&>(std::reference_wrapper<Fn volatile>(cl));
257         test_b34<int const volatile&>(std::reference_wrapper<Fn const volatile>(cl));
258     }
259     {
260         typedef DerivedFromTestClass Fn;
261         Fn cl(42);
262         test_b34<int&>(std::reference_wrapper<Fn>(cl));
263         test_b34<int const&>(std::reference_wrapper<Fn const>(cl));
264         test_b34<int volatile&>(std::reference_wrapper<Fn volatile>(cl));
265         test_b34<int const volatile&>(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&>(cl);
272         test_b34<int const&>(static_cast<Fn const*>(cl));
273         test_b34<int volatile&>(static_cast<Fn volatile*>(cl));
274         test_b34<int const volatile&>(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&>(cl);
281         test_b34<int const&>(static_cast<Fn const*>(cl));
282         test_b34<int volatile&>(static_cast<Fn volatile*>(cl));
283         test_b34<int const volatile&>(static_cast<Fn const volatile *>(cl));
284     }
285 }
286 
bullet_five_tests()287 void bullet_five_tests() {
288     using FooType = int&(NonCopyable&&);
289     {
290         FooType& fn = foo;
291         test_b5<int &>(fn);
292     }
293     {
294         FooType* fn = foo;
295         test_b5<int &>(fn);
296     }
297     {
298         typedef TestClass Fn;
299         Fn cl(42);
300         test_b5<int&>(cl);
301         test_b5<int const&>(static_cast<Fn const&>(cl));
302         test_b5<int volatile&>(static_cast<Fn volatile&>(cl));
303         test_b5<int const volatile&>(static_cast<Fn const volatile &>(cl));
304 
305         test_b5<int&&>(static_cast<Fn &&>(cl));
306         test_b5<int const&&>(static_cast<Fn const&&>(cl));
307         test_b5<int volatile&&>(static_cast<Fn volatile&&>(cl));
308         test_b5<int const volatile&&>(static_cast<Fn const volatile&&>(cl));
309     }
310 }
311 
312 struct CopyThrows {
CopyThrowsCopyThrows313   CopyThrows() {}
CopyThrowsCopyThrows314   CopyThrows(CopyThrows const&) {}
CopyThrowsCopyThrows315   CopyThrows(CopyThrows&&) noexcept {}
316 };
317 
318 struct NoThrowCallable {
operator ()NoThrowCallable319   void operator()() noexcept {}
operator ()NoThrowCallable320   void operator()(CopyThrows) noexcept {}
321 };
322 
323 struct ThrowsCallable {
operator ()ThrowsCallable324   void operator()() {}
325 };
326 
327 struct MemberObj {
328   int x;
329 };
330 
noexcept_test()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(obj)), "");
336         static_assert(!noexcept(std::invoke(obj, arg)), "");
337         static_assert(noexcept(std::invoke(obj, std::move(arg))), "");
338     }
339     {
340         ThrowsCallable obj; ((void)obj); // suppress unused warning
341         static_assert(!noexcept(std::invoke(obj)), "");
342     }
343     {
344         MemberObj obj{42}; ((void)obj); // suppress unused warning.
345         static_assert(noexcept(std::invoke(&MemberObj::x, obj)), "");
346     }
347 }
348 
349 // LWG3655: The INVOKE operation and union types
union_tests()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(&Union::x, get());
361         assert(result == 3);
362     }
363     {
364         auto get = []() -> Union const { return Union{.x = 3}; };
365         int result = std::invoke(&Union::x, get());
366         assert(result == 3);
367     }
368     {
369         Union u{3};
370         int& result = std::invoke(&Union::x, u);
371         assert(&result == &u.x);
372     }
373     {
374         Union const u{3};
375         int const& result = std::invoke(&Union::x, 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{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{3};
408         int result = std::invoke(&Union::g, u);
409         assert(result == 52);
410     }
411     {
412         Union const u{3};
413         int result = std::invoke(&Union::g, u);
414         assert(result == 52);
415     }
416 }
417 
main(int,char **)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