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