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, c++17 |
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 | // constexpr // constexpr in C++20 |
18 | // invoke_result_t<F, Args...> invoke(F&& f, Args&&... args) |
19 | // noexcept(is_nothrow_invocable_v<_Fn, _Args...>); |
20 | |
21 | /// C++14 [func.def] 20.9.0 |
22 | /// (1) The following definitions apply to this Clause: |
23 | /// (2) A call signature is the name of a return type followed by a parenthesized |
24 | /// comma-separated list of zero or more argument types. |
25 | /// (3) A callable type is a function object type (20.9) or a pointer to member. |
26 | /// (4) A callable object is an object of a callable type. |
27 | /// (5) A call wrapper type is a type that holds a callable object and supports |
28 | /// a call operation that forwards to that object. |
29 | /// (6) A call wrapper is an object of a call wrapper type. |
30 | /// (7) A target object is the callable object held by a call wrapper. |
31 | |
32 | /// C++14 [func.require] 20.9.1 |
33 | /// |
34 | /// Define INVOKE (f, t1, t2, ..., tN) as follows: |
35 | /// (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 |
36 | /// type T or a reference to an object of type T or a reference to an object of a type derived from T; |
37 | /// (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 |
38 | /// the types described in the previous item; |
39 | /// (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 |
40 | /// reference to an object of type T or a reference to an object of a type derived from T; |
41 | /// (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 |
42 | /// described in the previous item; |
43 | /// (1.5) - f(t1, t2, ..., tN) in all other cases. |
44 | |
45 | #include <functional> |
46 | #include <type_traits> |
47 | #include <utility> // for std::move |
48 | #include <cassert> |
49 | |
50 | #include "test_macros.h" |
51 | |
52 | struct NonCopyable { |
53 | constexpr NonCopyable() {} |
54 | private: |
55 | NonCopyable(NonCopyable const&) = delete; |
56 | NonCopyable& operator=(NonCopyable const&) = delete; |
57 | }; |
58 | |
59 | struct TestClass { |
60 | constexpr explicit TestClass(int x) : data(x) {} |
61 | |
62 | constexpr int& operator()(NonCopyable&&) & { return data; } |
63 | constexpr int const& operator()(NonCopyable&&) const & { return data; } |
64 | |
65 | constexpr int&& operator()(NonCopyable&&) && { return std::move(data); } |
66 | constexpr int const&& operator()(NonCopyable&&) const && { return std::move(data); } |
67 | |
68 | int data; |
69 | private: |
70 | TestClass(TestClass const&) = delete; |
71 | TestClass& operator=(TestClass const&) = delete; |
72 | }; |
73 | |
74 | struct DerivedFromTestClass : public TestClass { |
75 | constexpr explicit DerivedFromTestClass(int x) : TestClass(x) {} |
76 | }; |
77 | |
78 | static constexpr int data = 42; |
79 | constexpr const int& foo(NonCopyable&&) { |
80 | return data; |
81 | } |
82 | |
83 | template <class Signature, class Expect, class Functor> |
84 | constexpr void test_b12(Functor&& f) { |
85 | // Create the callable object. |
86 | typedef Signature TestClass::*ClassFunc; |
87 | ClassFunc func_ptr = &TestClass::operator(); |
88 | |
89 | // Create the dummy arg. |
90 | NonCopyable arg; |
91 | |
92 | // Check that the deduced return type of invoke is what is expected. |
93 | typedef decltype( |
94 | std::invoke(func_ptr, std::forward<Functor>(f), std::move(arg)) |
95 | ) DeducedReturnType; |
96 | static_assert((std::is_same<DeducedReturnType, Expect>::value), "" ); |
97 | |
98 | // Check that result_of_t matches Expect. |
99 | typedef typename std::result_of<ClassFunc&&(Functor&&, NonCopyable&&)>::type |
100 | ResultOfReturnType; |
101 | static_assert((std::is_same<ResultOfReturnType, Expect>::value), "" ); |
102 | |
103 | // Run invoke and check the return value. |
104 | DeducedReturnType ret = |
105 | std::invoke(func_ptr, std::forward<Functor>(f), std::move(arg)); |
106 | assert(ret == 42); |
107 | } |
108 | |
109 | template <class Expect, class Functor> |
110 | constexpr void test_b34(Functor&& f) { |
111 | // Create the callable object. |
112 | typedef int TestClass::*ClassFunc; |
113 | ClassFunc func_ptr = &TestClass::data; |
114 | |
115 | // Check that the deduced return type of invoke is what is expected. |
116 | typedef decltype( |
117 | std::invoke(func_ptr, std::forward<Functor>(f)) |
118 | ) DeducedReturnType; |
119 | static_assert((std::is_same<DeducedReturnType, Expect>::value), "" ); |
120 | |
121 | // Check that result_of_t matches Expect. |
122 | typedef typename std::result_of<ClassFunc&&(Functor&&)>::type |
123 | ResultOfReturnType; |
124 | static_assert((std::is_same<ResultOfReturnType, Expect>::value), "" ); |
125 | |
126 | // Run invoke and check the return value. |
127 | DeducedReturnType ret = |
128 | std::invoke(func_ptr, std::forward<Functor>(f)); |
129 | assert(ret == 42); |
130 | } |
131 | |
132 | template <class Expect, class Functor> |
133 | constexpr void test_b5(Functor&& f) { |
134 | NonCopyable arg; |
135 | |
136 | // Check that the deduced return type of invoke is what is expected. |
137 | typedef decltype( |
138 | std::invoke(std::forward<Functor>(f), std::move(arg)) |
139 | ) DeducedReturnType; |
140 | static_assert((std::is_same<DeducedReturnType, Expect>::value), "" ); |
141 | |
142 | // Check that result_of_t matches Expect. |
143 | typedef typename std::result_of<Functor&&(NonCopyable&&)>::type |
144 | ResultOfReturnType; |
145 | static_assert((std::is_same<ResultOfReturnType, Expect>::value), "" ); |
146 | |
147 | // Run invoke and check the return value. |
148 | DeducedReturnType ret = std::invoke(std::forward<Functor>(f), std::move(arg)); |
149 | assert(ret == 42); |
150 | } |
151 | |
152 | constexpr bool bullet_one_two_tests() { |
153 | { |
154 | TestClass cl(42); |
155 | test_b12<int&(NonCopyable&&) &, int&>(f&: cl); |
156 | test_b12<int const&(NonCopyable&&) const &, int const&>(f&: cl); |
157 | |
158 | test_b12<int&&(NonCopyable&&) &&, int&&>(f: std::move(cl)); |
159 | test_b12<int const&&(NonCopyable&&) const &&, int const&&>(f: std::move(cl)); |
160 | } |
161 | { |
162 | DerivedFromTestClass cl(42); |
163 | test_b12<int&(NonCopyable&&) &, int&>(f&: cl); |
164 | test_b12<int const&(NonCopyable&&) const &, int const&>(f&: cl); |
165 | |
166 | test_b12<int&&(NonCopyable&&) &&, int&&>(f: std::move(cl)); |
167 | test_b12<int const&&(NonCopyable&&) const &&, int const&&>(f: std::move(cl)); |
168 | } |
169 | { |
170 | TestClass cl_obj(42); |
171 | std::reference_wrapper<TestClass> cl(cl_obj); |
172 | test_b12<int&(NonCopyable&&) &, int&>(f&: cl); |
173 | test_b12<int const&(NonCopyable&&) const &, int const&>(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 | } |
178 | { |
179 | DerivedFromTestClass cl_obj(42); |
180 | std::reference_wrapper<DerivedFromTestClass> cl(cl_obj); |
181 | test_b12<int&(NonCopyable&&) &, int&>(f&: cl); |
182 | test_b12<int const&(NonCopyable&&) const &, int const&>(f&: cl); |
183 | |
184 | test_b12<int&(NonCopyable&&) &, int&>(f: std::move(cl)); |
185 | test_b12<int const&(NonCopyable&&) const &, int const&>(f: std::move(cl)); |
186 | } |
187 | { |
188 | TestClass cl_obj(42); |
189 | TestClass *cl = &cl_obj; |
190 | test_b12<int&(NonCopyable&&) &, int&>(f&: cl); |
191 | test_b12<int const&(NonCopyable&&) const &, int const&>(f&: cl); |
192 | } |
193 | { |
194 | DerivedFromTestClass cl_obj(42); |
195 | DerivedFromTestClass *cl = &cl_obj; |
196 | test_b12<int&(NonCopyable&&) &, int&>(f&: cl); |
197 | test_b12<int const&(NonCopyable&&) const &, int const&>(f&: cl); |
198 | } |
199 | return true; |
200 | } |
201 | |
202 | constexpr bool bullet_three_four_tests() { |
203 | { |
204 | typedef TestClass Fn; |
205 | Fn cl(42); |
206 | test_b34<int&>(f&: cl); |
207 | test_b34<int const&>(f: static_cast<Fn const&>(cl)); |
208 | |
209 | test_b34<int&&>(f: static_cast<Fn &&>(cl)); |
210 | test_b34<int const&&>(f: static_cast<Fn const&&>(cl)); |
211 | } |
212 | { |
213 | typedef DerivedFromTestClass Fn; |
214 | Fn cl(42); |
215 | test_b34<int&>(f&: cl); |
216 | test_b34<int const&>(f: static_cast<Fn const&>(cl)); |
217 | |
218 | test_b34<int&&>(f: static_cast<Fn &&>(cl)); |
219 | test_b34<int const&&>(f: static_cast<Fn const&&>(cl)); |
220 | } |
221 | { |
222 | typedef TestClass Fn; |
223 | Fn cl(42); |
224 | test_b34<int&>(f: std::reference_wrapper<Fn>(cl)); |
225 | test_b34<int const&>(f: std::reference_wrapper<Fn const>(cl)); |
226 | } |
227 | { |
228 | typedef DerivedFromTestClass Fn; |
229 | Fn cl(42); |
230 | test_b34<int&>(f: std::reference_wrapper<Fn>(cl)); |
231 | test_b34<int const&>(f: std::reference_wrapper<Fn const>(cl)); |
232 | } |
233 | { |
234 | typedef TestClass Fn; |
235 | Fn cl_obj(42); |
236 | Fn* cl = &cl_obj; |
237 | test_b34<int&>(f&: cl); |
238 | test_b34<int const&>(f: static_cast<Fn const*>(cl)); |
239 | } |
240 | { |
241 | typedef DerivedFromTestClass Fn; |
242 | Fn cl_obj(42); |
243 | Fn* cl = &cl_obj; |
244 | test_b34<int&>(f&: cl); |
245 | test_b34<int const&>(f: static_cast<Fn const*>(cl)); |
246 | } |
247 | return true; |
248 | } |
249 | |
250 | constexpr bool bullet_five_tests() { |
251 | using = const int&(NonCopyable&&); |
252 | { |
253 | FooType& fn = foo; |
254 | test_b5<const int &>(f&: fn); |
255 | } |
256 | { |
257 | FooType* fn = foo; |
258 | test_b5<const int &>(f&: fn); |
259 | } |
260 | { |
261 | typedef TestClass Fn; |
262 | Fn cl(42); |
263 | test_b5<int&>(f&: cl); |
264 | test_b5<int const&>(f: static_cast<Fn const&>(cl)); |
265 | |
266 | test_b5<int&&>(f: static_cast<Fn &&>(cl)); |
267 | test_b5<int const&&>(f: static_cast<Fn const&&>(cl)); |
268 | } |
269 | return true; |
270 | } |
271 | |
272 | int main(int, char**) { |
273 | bullet_one_two_tests(); |
274 | bullet_three_four_tests(); |
275 | bullet_five_tests(); |
276 | |
277 | static_assert(bullet_one_two_tests()); |
278 | static_assert(bullet_three_four_tests()); |
279 | static_assert(bullet_five_tests()); |
280 | |
281 | return 0; |
282 | } |
283 | |