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
51struct NonCopyable {
52 NonCopyable() {}
53private:
54 NonCopyable(NonCopyable const&) = delete;
55 NonCopyable& operator=(NonCopyable const&) = delete;
56};
57
58struct 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;
72private:
73 TestClass(TestClass const&) = delete;
74 TestClass& operator=(TestClass const&) = delete;
75};
76
77struct DerivedFromTestClass : public TestClass {
78 explicit DerivedFromTestClass(int x) : TestClass(x) {}
79};
80
81int& foo(NonCopyable&&) {
82 static int data = 42;
83 return data;
84}
85
86template <class Signature, class Expect, class Functor>
87void 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
112template <class Expect, class Functor>
113void 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
135template <class Expect, class Functor>
136void 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
155void 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
224void 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
287void bullet_five_tests() {
288 using FooType = 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
312struct CopyThrows {
313 CopyThrows() {}
314 CopyThrows(CopyThrows const&) {}
315 CopyThrows(CopyThrows&&) noexcept {}
316};
317
318struct NoThrowCallable {
319 void operator()() noexcept {}
320 void operator()(CopyThrows) noexcept {}
321};
322
323struct ThrowsCallable {
324 void operator()() {}
325};
326
327struct MemberObj {
328 int x;
329};
330
331void 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
350void 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
418int 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

source code of libcxx/test/std/utilities/function.objects/func.invoke/invoke.pass.cpp