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