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
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);
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
192void 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
239void 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
264int main() {
265    bullet_one_two_tests();
266    bullet_three_four_tests();
267    bullet_five_tests();
268}
269