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++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: 30 /// (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 31 /// type T or a reference to an object of type T or a reference to an object of a type derived from T; 32 /// (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 33 /// the types described in the previous item; 34 /// (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 35 /// reference to an object of type T or a reference to an object of a type derived from T; 36 /// (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 37 /// described in the previous item; 38 /// (1.5) - f(t1, t2, ..., tN) in all other cases. 39 40 #include <functional> 41 #include <type_traits> 42 #include <utility> // for std::move 43 #include <cassert> 44 45 struct NonCopyable { 46 NonCopyable() {} 47 private: 48 NonCopyable(NonCopyable const&) = delete; 49 NonCopyable& operator=(NonCopyable const&) = delete; 50 }; 51 52 struct 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; 66 private: 67 TestClass(TestClass const&) = delete; 68 TestClass& operator=(TestClass const&) = delete; 69 }; 70 71 struct DerivedFromTestClass : public TestClass { 72 explicit DerivedFromTestClass(int x) : TestClass(x) {} 73 }; 74 75 int& foo(NonCopyable&&) { 76 static int data = 42; 77 return data; 78 } 79 80 template <class Signature, class Expect, class Functor> 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> 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> 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 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 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); 202 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 218 void 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; 247 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; 263 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 281 void 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 306 struct CopyThrows { 307 CopyThrows() {} 308 CopyThrows(CopyThrows const&) {} 309 CopyThrows(CopyThrows&&) noexcept {} 310 }; 311 312 struct NoThrowCallable { 313 void operator()() noexcept {} 314 void operator()(CopyThrows) noexcept {} 315 }; 316 317 struct ThrowsCallable { 318 void operator()() {} 319 }; 320 321 struct MemberObj { 322 int x; 323 }; 324 325 void noexcept_test() { 326 { 327 NoThrowCallable obj; ((void)obj); // suppress unused warning 328 CopyThrows arg; ((void)arg); // suppress unused warning 329 static_assert(noexcept(std::invoke(obj)), ""); 330 static_assert(!noexcept(std::invoke(obj, arg)), ""); 331 static_assert(noexcept(std::invoke(obj, std::move(arg))), ""); 332 } 333 { 334 ThrowsCallable obj; ((void)obj); // suppress unused warning 335 static_assert(!noexcept(std::invoke(obj)), ""); 336 } 337 { 338 MemberObj obj{42}; ((void)obj); // suppress unused warning. 339 static_assert(noexcept(std::invoke(&MemberObj::x, obj)), ""); 340 } 341 } 342 343 int main() { 344 bullet_one_two_tests(); 345 bullet_three_four_tests(); 346 bullet_five_tests(); 347 noexcept_test(); 348 } 349