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 <cassert>
44 
45 struct NonCopyable {
NonCopyableNonCopyable46     NonCopyable() {}
47 private:
48     NonCopyable(NonCopyable const&) = delete;
49     NonCopyable& operator=(NonCopyable const&) = delete;
50 };
51 
52 struct TestClass {
TestClassTestClass53     explicit TestClass(int x) : data(x) {}
54 
operator ()TestClass55     int& operator()(NonCopyable&&) & { return data; }
operator ()TestClass56     int const& operator()(NonCopyable&&) const & { return data; }
operator ()TestClass57     int volatile& operator()(NonCopyable&&) volatile & { return data; }
operator ()TestClass58     int const volatile& operator()(NonCopyable&&) const volatile & { return data; }
59 
operator ()TestClass60     int&& operator()(NonCopyable&&) && { return std::move(data); }
operator ()TestClass61     int const&& operator()(NonCopyable&&) const && { return std::move(data); }
operator ()TestClass62     int volatile&& operator()(NonCopyable&&) volatile && { return std::move(data); }
operator ()TestClass63     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 {
DerivedFromTestClassDerivedFromTestClass72     explicit DerivedFromTestClass(int x) : TestClass(x) {}
73 };
74 
foo(NonCopyable &&)75 int& foo(NonCopyable&&) {
76     static int data = 42;
77     return data;
78 }
79 
80 template <class Signature,  class Expect, class Functor>
test_b12(Functor && f)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>
test_b34(Functor && f)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>
test_b5(Functor && f)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 
bullet_one_two_tests()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         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     {
183         DerivedFromTestClass cl_obj(42);
184         DerivedFromTestClass *cl = &cl_obj;
185         test_b12<int&(NonCopyable&&) &, int&>(cl);
186         test_b12<int const&(NonCopyable&&) const &, int const&>(cl);
187         test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(cl);
188         test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(cl);
189     }
190 }
191 
bullet_three_four_tests()192 void bullet_three_four_tests() {
193     {
194         typedef TestClass Fn;
195         Fn cl(42);
196         test_b34<int&>(cl);
197         test_b34<int const&>(static_cast<Fn const&>(cl));
198         test_b34<int volatile&>(static_cast<Fn volatile&>(cl));
199         test_b34<int const volatile&>(static_cast<Fn const volatile &>(cl));
200 
201         test_b34<int&&>(static_cast<Fn &&>(cl));
202         test_b34<int const&&>(static_cast<Fn const&&>(cl));
203         test_b34<int volatile&&>(static_cast<Fn volatile&&>(cl));
204         test_b34<int const volatile&&>(static_cast<Fn const volatile&&>(cl));
205     }
206     {
207         typedef DerivedFromTestClass Fn;
208         Fn cl(42);
209         test_b34<int&>(cl);
210         test_b34<int const&>(static_cast<Fn const&>(cl));
211         test_b34<int volatile&>(static_cast<Fn volatile&>(cl));
212         test_b34<int const volatile&>(static_cast<Fn const volatile &>(cl));
213 
214         test_b34<int&&>(static_cast<Fn &&>(cl));
215         test_b34<int const&&>(static_cast<Fn const&&>(cl));
216         test_b34<int volatile&&>(static_cast<Fn volatile&&>(cl));
217         test_b34<int const volatile&&>(static_cast<Fn const volatile&&>(cl));
218     }
219     {
220         typedef TestClass Fn;
221         Fn cl_obj(42);
222         Fn* cl = &cl_obj;
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     {
229         typedef DerivedFromTestClass Fn;
230         Fn cl_obj(42);
231         Fn* cl = &cl_obj;
232         test_b34<int&>(cl);
233         test_b34<int const&>(static_cast<Fn const*>(cl));
234         test_b34<int volatile&>(static_cast<Fn volatile*>(cl));
235         test_b34<int const volatile&>(static_cast<Fn const volatile *>(cl));
236     }
237 }
238 
bullet_five_tests()239 void bullet_five_tests() {
240     using FooType = int&(NonCopyable&&);
241     {
242         FooType& fn = foo;
243         test_b5<int &>(fn);
244     }
245     {
246         FooType* fn = foo;
247         test_b5<int &>(fn);
248     }
249     {
250         typedef TestClass Fn;
251         Fn cl(42);
252         test_b5<int&>(cl);
253         test_b5<int const&>(static_cast<Fn const&>(cl));
254         test_b5<int volatile&>(static_cast<Fn volatile&>(cl));
255         test_b5<int const volatile&>(static_cast<Fn const volatile &>(cl));
256 
257         test_b5<int&&>(static_cast<Fn &&>(cl));
258         test_b5<int const&&>(static_cast<Fn const&&>(cl));
259         test_b5<int volatile&&>(static_cast<Fn volatile&&>(cl));
260         test_b5<int const volatile&&>(static_cast<Fn const volatile&&>(cl));
261     }
262 }
263 
main()264 int main() {
265     bullet_one_two_tests();
266     bullet_three_four_tests();
267     bullet_five_tests();
268 }
269