blob: b0a41447e05a214a5f4ef175fbadd82a02faa80f [file] [log] [blame]
Eric Fiselier5be45122015-07-14 20:16:15 +00001//===----------------------------------------------------------------------===//
2//
Chandler Carruth57b08b02019-01-19 10:56:40 +00003// 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
Eric Fiselier5be45122015-07-14 20:16:15 +00006//
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:
Eric Fiselier16270a02015-07-14 20:45:48 +000030/// (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
Eric Fiselier5be45122015-07-14 20:16:15 +000031/// type T or a reference to an object of type T or a reference to an object of a type derived from T;
Eric Fiselier16270a02015-07-14 20:45:48 +000032/// (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
Eric Fiselier5be45122015-07-14 20:16:15 +000033/// the types described in the previous item;
Eric Fiselier16270a02015-07-14 20:45:48 +000034/// (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
Eric Fiselier5be45122015-07-14 20:16:15 +000035/// reference to an object of type T or a reference to an object of a type derived from T;
Eric Fiselier16270a02015-07-14 20:45:48 +000036/// (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
Eric Fiselier5be45122015-07-14 20:16:15 +000037/// described in the previous item;
Eric Fiselier16270a02015-07-14 20:45:48 +000038/// (1.5) - f(t1, t2, ..., tN) in all other cases.
Eric Fiselier5be45122015-07-14 20:16:15 +000039
40#include <functional>
41#include <type_traits>
Marshall Clowd1180f42015-11-10 16:10:17 +000042#include <utility> // for std::move
Eric Fiselier5be45122015-07-14 20:16:15 +000043#include <cassert>
44
45struct NonCopyable {
46 NonCopyable() {}
47private:
48 NonCopyable(NonCopyable const&) = delete;
49 NonCopyable& operator=(NonCopyable const&) = delete;
50};
51
52struct 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;
66private:
67 TestClass(TestClass const&) = delete;
68 TestClass& operator=(TestClass const&) = delete;
69};
70
71struct DerivedFromTestClass : public TestClass {
72 explicit DerivedFromTestClass(int x) : TestClass(x) {}
73};
74
75int& foo(NonCopyable&&) {
76 static int data = 42;
77 return data;
78}
79
80template <class Signature, class Expect, class Functor>
81void 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
106template <class Expect, class Functor>
107void 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
129template <class Expect, class Functor>
130void 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
149void 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);
Eric Fiselier2152fd72016-04-18 06:17:30 +0000176 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);
Eric Fiselier5be45122015-07-14 20:16:15 +0000202 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
218void 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;
Eric Fiselier2152fd72016-04-18 06:17:30 +0000247 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;
Eric Fiselier5be45122015-07-14 20:16:15 +0000263 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
281void 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
Eric Fiselier57257562016-06-02 01:25:41 +0000306struct CopyThrows {
307 CopyThrows() {}
308 CopyThrows(CopyThrows const&) {}
309 CopyThrows(CopyThrows&&) noexcept {}
310};
311
312struct NoThrowCallable {
313 void operator()() noexcept {}
314 void operator()(CopyThrows) noexcept {}
315};
316
317struct ThrowsCallable {
318 void operator()() {}
319};
320
321struct MemberObj {
322 int x;
323};
324
325void noexcept_test() {
326 {
Eric Fiselierc1d08ff2016-06-22 00:58:06 +0000327 NoThrowCallable obj; ((void)obj); // suppress unused warning
328 CopyThrows arg; ((void)arg); // suppress unused warning
Eric Fiselier7a580d02016-06-22 01:10:14 +0000329 static_assert(noexcept(std::invoke(obj)), "");
330 static_assert(!noexcept(std::invoke(obj, arg)), "");
331 static_assert(noexcept(std::invoke(obj, std::move(arg))), "");
Eric Fiselier57257562016-06-02 01:25:41 +0000332 }
333 {
Eric Fiselierc1d08ff2016-06-22 00:58:06 +0000334 ThrowsCallable obj; ((void)obj); // suppress unused warning
Eric Fiselier7a580d02016-06-22 01:10:14 +0000335 static_assert(!noexcept(std::invoke(obj)), "");
Eric Fiselier57257562016-06-02 01:25:41 +0000336 }
337 {
Eric Fiselierc1d08ff2016-06-22 00:58:06 +0000338 MemberObj obj{42}; ((void)obj); // suppress unused warning.
Eric Fiselier7a580d02016-06-22 01:10:14 +0000339 static_assert(noexcept(std::invoke(&MemberObj::x, obj)), "");
Eric Fiselier57257562016-06-02 01:25:41 +0000340 }
341}
342
Eric Fiselier5be45122015-07-14 20:16:15 +0000343int main() {
344 bullet_one_two_tests();
345 bullet_three_four_tests();
346 bullet_five_tests();
Eric Fiselier57257562016-06-02 01:25:41 +0000347 noexcept_test();
Eric Fiselier5be45122015-07-14 20:16:15 +0000348}