426 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++1410 11// <functional>12 13// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_CXX20_REMOVED_TYPE_TRAITS14// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS15 16// template<class F, class... Args>17// invoke_result_t<F, Args...> invoke(F&& f, Args&&... args) // C++1718// noexcept(is_nothrow_invocable_v<_Fn, _Args...>);19 20/// C++14 [func.def] 20.9.021/// (1) The following definitions apply to this Clause:22/// (2) A call signature is the name of a return type followed by a parenthesized23/// comma-separated list of zero or more argument types.24/// (3) A callable type is a function object type (20.9) or a pointer to member.25/// (4) A callable object is an object of a callable type.26/// (5) A call wrapper type is a type that holds a callable object and supports27/// a call operation that forwards to that object.28/// (6) A call wrapper is an object of a call wrapper type.29/// (7) A target object is the callable object held by a call wrapper.30 31/// C++14 [func.require] 20.9.132///33/// Define INVOKE (f, t1, t2, ..., tN) as follows:34/// (1.1) - (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is an object of35/// type T or a reference to an object of type T or a reference to an object of a type derived from T;36/// (1.2) - ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is not one of37/// the types described in the previous item;38/// (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 a39/// reference to an object of type T or a reference to an object of a type derived from T;40/// (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 types41/// described in the previous item;42/// (1.5) - f(t1, t2, ..., tN) in all other cases.43 44#include <functional>45#include <type_traits>46#include <utility> // for std::move47#include <cassert>48 49#include "test_macros.h"50 51struct NonCopyable {52 NonCopyable() {}53private:54 NonCopyable(NonCopyable const&) = delete;55 NonCopyable& operator=(NonCopyable const&) = delete;56};57 58struct TestClass {59 explicit TestClass(int x) : data(x) {}60 61 int& operator()(NonCopyable&&) & { return data; }62 int const& operator()(NonCopyable&&) const & { return data; }63 int volatile& operator()(NonCopyable&&) volatile & { return data; }64 int const volatile& operator()(NonCopyable&&) const volatile & { return data; }65 66 int&& operator()(NonCopyable&&) && { return std::move(data); }67 int const&& operator()(NonCopyable&&) const && { return std::move(data); }68 int volatile&& operator()(NonCopyable&&) volatile && { return std::move(data); }69 int const volatile&& operator()(NonCopyable&&) const volatile && { return std::move(data); }70 71 int data;72private:73 TestClass(TestClass const&) = delete;74 TestClass& operator=(TestClass const&) = delete;75};76 77struct DerivedFromTestClass : public TestClass {78 explicit DerivedFromTestClass(int x) : TestClass(x) {}79};80 81int& foo(NonCopyable&&) {82 static int data = 42;83 return data;84}85 86template <class Signature, class Expect, class Functor>87void test_b12(Functor&& f) {88 // Create the callable object.89 typedef Signature TestClass::*ClassFunc;90 ClassFunc func_ptr = &TestClass::operator();91 92 // Create the dummy arg.93 NonCopyable arg;94 95 // Check that the deduced return type of invoke is what is expected.96 typedef decltype(97 std::invoke(func_ptr, std::forward<Functor>(f), std::move(arg))98 ) DeducedReturnType;99 static_assert((std::is_same<DeducedReturnType, Expect>::value), "");100 101 // Check that result_of_t matches Expect.102 typedef typename std::result_of<ClassFunc&&(Functor&&, NonCopyable&&)>::type103 ResultOfReturnType;104 static_assert((std::is_same<ResultOfReturnType, Expect>::value), "");105 106 // Run invoke and check the return value.107 DeducedReturnType ret =108 std::invoke(func_ptr, std::forward<Functor>(f), std::move(arg));109 assert(ret == 42);110}111 112template <class Expect, class Functor>113void test_b34(Functor&& f) {114 // Create the callable object.115 typedef int TestClass::*ClassFunc;116 ClassFunc func_ptr = &TestClass::data;117 118 // Check that the deduced return type of invoke is what is expected.119 typedef decltype(120 std::invoke(func_ptr, std::forward<Functor>(f))121 ) DeducedReturnType;122 static_assert((std::is_same<DeducedReturnType, Expect>::value), "");123 124 // Check that result_of_t matches Expect.125 typedef typename std::result_of<ClassFunc&&(Functor&&)>::type126 ResultOfReturnType;127 static_assert((std::is_same<ResultOfReturnType, Expect>::value), "");128 129 // Run invoke and check the return value.130 DeducedReturnType ret =131 std::invoke(func_ptr, std::forward<Functor>(f));132 assert(ret == 42);133}134 135template <class Expect, class Functor>136void test_b5(Functor&& f) {137 NonCopyable arg;138 139 // Check that the deduced return type of invoke is what is expected.140 typedef decltype(141 std::invoke(std::forward<Functor>(f), std::move(arg))142 ) DeducedReturnType;143 static_assert((std::is_same<DeducedReturnType, Expect>::value), "");144 145 // Check that result_of_t matches Expect.146 typedef typename std::result_of<Functor&&(NonCopyable&&)>::type147 ResultOfReturnType;148 static_assert((std::is_same<ResultOfReturnType, Expect>::value), "");149 150 // Run invoke and check the return value.151 DeducedReturnType ret = std::invoke(std::forward<Functor>(f), std::move(arg));152 assert(ret == 42);153}154 155void bullet_one_two_tests() {156 {157 TestClass cl(42);158 test_b12<int&(NonCopyable&&) &, int&>(cl);159 test_b12<int const&(NonCopyable&&) const &, int const&>(cl);160 test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(cl);161 test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(cl);162 163 test_b12<int&&(NonCopyable&&) &&, int&&>(std::move(cl));164 test_b12<int const&&(NonCopyable&&) const &&, int const&&>(std::move(cl));165 test_b12<int volatile&&(NonCopyable&&) volatile &&, int volatile&&>(std::move(cl));166 test_b12<int const volatile&&(NonCopyable&&) const volatile &&, int const volatile&&>(std::move(cl));167 }168 {169 DerivedFromTestClass cl(42);170 test_b12<int&(NonCopyable&&) &, int&>(cl);171 test_b12<int const&(NonCopyable&&) const &, int const&>(cl);172 test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(cl);173 test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(cl);174 175 test_b12<int&&(NonCopyable&&) &&, int&&>(std::move(cl));176 test_b12<int const&&(NonCopyable&&) const &&, int const&&>(std::move(cl));177 test_b12<int volatile&&(NonCopyable&&) volatile &&, int volatile&&>(std::move(cl));178 test_b12<int const volatile&&(NonCopyable&&) const volatile &&, int const volatile&&>(std::move(cl));179 }180 {181 TestClass cl_obj(42);182 std::reference_wrapper<TestClass> cl(cl_obj);183 test_b12<int&(NonCopyable&&) &, int&>(cl);184 test_b12<int const&(NonCopyable&&) const &, int const&>(cl);185 test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(cl);186 test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(cl);187 188 test_b12<int&(NonCopyable&&) &, int&>(std::move(cl));189 test_b12<int const&(NonCopyable&&) const &, int const&>(std::move(cl));190 test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(std::move(cl));191 test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(std::move(cl));192 }193 {194 DerivedFromTestClass cl_obj(42);195 std::reference_wrapper<DerivedFromTestClass> cl(cl_obj);196 test_b12<int&(NonCopyable&&) &, int&>(cl);197 test_b12<int const&(NonCopyable&&) const &, int const&>(cl);198 test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(cl);199 test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(cl);200 201 test_b12<int&(NonCopyable&&) &, int&>(std::move(cl));202 test_b12<int const&(NonCopyable&&) const &, int const&>(std::move(cl));203 test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(std::move(cl));204 test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(std::move(cl));205 }206 {207 TestClass cl_obj(42);208 TestClass *cl = &cl_obj;209 test_b12<int&(NonCopyable&&) &, int&>(cl);210 test_b12<int const&(NonCopyable&&) const &, int const&>(cl);211 test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(cl);212 test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(cl);213 }214 {215 DerivedFromTestClass cl_obj(42);216 DerivedFromTestClass *cl = &cl_obj;217 test_b12<int&(NonCopyable&&) &, int&>(cl);218 test_b12<int const&(NonCopyable&&) const &, int const&>(cl);219 test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(cl);220 test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(cl);221 }222}223 224void bullet_three_four_tests() {225 {226 typedef TestClass Fn;227 Fn cl(42);228 test_b34<int&>(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 test_b34<int&&>(static_cast<Fn &&>(cl));234 test_b34<int const&&>(static_cast<Fn const&&>(cl));235 test_b34<int volatile&&>(static_cast<Fn volatile&&>(cl));236 test_b34<int const volatile&&>(static_cast<Fn const volatile&&>(cl));237 }238 {239 typedef DerivedFromTestClass Fn;240 Fn cl(42);241 test_b34<int&>(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 test_b34<int&&>(static_cast<Fn &&>(cl));247 test_b34<int const&&>(static_cast<Fn const&&>(cl));248 test_b34<int volatile&&>(static_cast<Fn volatile&&>(cl));249 test_b34<int const volatile&&>(static_cast<Fn const volatile&&>(cl));250 }251 {252 typedef TestClass Fn;253 Fn cl(42);254 test_b34<int&>(std::reference_wrapper<Fn>(cl));255 test_b34<int const&>(std::reference_wrapper<Fn const>(cl));256 test_b34<int volatile&>(std::reference_wrapper<Fn volatile>(cl));257 test_b34<int const volatile&>(std::reference_wrapper<Fn const volatile>(cl));258 }259 {260 typedef DerivedFromTestClass Fn;261 Fn cl(42);262 test_b34<int&>(std::reference_wrapper<Fn>(cl));263 test_b34<int const&>(std::reference_wrapper<Fn const>(cl));264 test_b34<int volatile&>(std::reference_wrapper<Fn volatile>(cl));265 test_b34<int const volatile&>(std::reference_wrapper<Fn const volatile>(cl));266 }267 {268 typedef TestClass Fn;269 Fn cl_obj(42);270 Fn* cl = &cl_obj;271 test_b34<int&>(cl);272 test_b34<int const&>(static_cast<Fn const*>(cl));273 test_b34<int volatile&>(static_cast<Fn volatile*>(cl));274 test_b34<int const volatile&>(static_cast<Fn const volatile *>(cl));275 }276 {277 typedef DerivedFromTestClass Fn;278 Fn cl_obj(42);279 Fn* cl = &cl_obj;280 test_b34<int&>(cl);281 test_b34<int const&>(static_cast<Fn const*>(cl));282 test_b34<int volatile&>(static_cast<Fn volatile*>(cl));283 test_b34<int const volatile&>(static_cast<Fn const volatile *>(cl));284 }285}286 287void bullet_five_tests() {288 using FooType = int&(NonCopyable&&);289 {290 FooType& fn = foo;291 test_b5<int &>(fn);292 }293 {294 FooType* fn = foo;295 test_b5<int &>(fn);296 }297 {298 typedef TestClass Fn;299 Fn cl(42);300 test_b5<int&>(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 test_b5<int&&>(static_cast<Fn &&>(cl));306 test_b5<int const&&>(static_cast<Fn const&&>(cl));307 test_b5<int volatile&&>(static_cast<Fn volatile&&>(cl));308 test_b5<int const volatile&&>(static_cast<Fn const volatile&&>(cl));309 }310}311 312struct CopyThrows {313 CopyThrows() {}314 CopyThrows(CopyThrows const&) {}315 CopyThrows(CopyThrows&&) noexcept {}316};317 318struct NoThrowCallable {319 void operator()() noexcept {}320 void operator()(CopyThrows) noexcept {}321};322 323struct ThrowsCallable {324 void operator()() {}325};326 327struct MemberObj {328 int x;329};330 331void noexcept_test() {332 {333 NoThrowCallable obj; ((void)obj); // suppress unused warning334 CopyThrows arg; ((void)arg); // suppress unused warning335 static_assert(noexcept(std::invoke(obj)), "");336 static_assert(!noexcept(std::invoke(obj, arg)), "");337 static_assert(noexcept(std::invoke(obj, std::move(arg))), "");338 }339 {340 ThrowsCallable obj; ((void)obj); // suppress unused warning341 static_assert(!noexcept(std::invoke(obj)), "");342 }343 {344 MemberObj obj{42}; ((void)obj); // suppress unused warning.345 static_assert(noexcept(std::invoke(&MemberObj::x, obj)), "");346 }347}348 349// LWG3655: The INVOKE operation and union types350void union_tests() {351 union Union {352 int x;353 int f() { return 42; }354 int g() const { return 52; }355 };356 357 // With a data member358 {359 auto get = []() -> Union { return Union{.x = 3}; };360 int result = std::invoke(&Union::x, get());361 assert(result == 3);362 }363 {364 auto get = []() -> Union const { return Union{.x = 3}; };365 int result = std::invoke(&Union::x, get());366 assert(result == 3);367 }368 {369 Union u{3};370 int& result = std::invoke(&Union::x, u);371 assert(&result == &u.x);372 }373 {374 Union const u{3};375 int const& result = std::invoke(&Union::x, u);376 assert(&result == &u.x);377 }378 379 // With a pointer to a member function380 {381 auto get = []() -> Union { return Union{.x = 3}; };382 int result = std::invoke(&Union::f, get());383 assert(result == 42);384 }385 {386 Union u{3};387 int result = std::invoke(&Union::f, u);388 assert(result == 42);389 }390 {391 // constness mismatch392 static_assert(!std::is_invocable_v<int (Union::*)(), Union const>);393 static_assert(!std::is_invocable_v<int (Union::*)(), Union const&>);394 }395 396 {397 auto get = []() -> Union { return Union{.x = 3}; };398 int result = std::invoke(&Union::g, get());399 assert(result == 52);400 }401 {402 auto get = []() -> Union const { return Union{.x = 3}; };403 int result = std::invoke(&Union::g, get());404 assert(result == 52);405 }406 {407 Union u{3};408 int result = std::invoke(&Union::g, u);409 assert(result == 52);410 }411 {412 Union const u{3};413 int result = std::invoke(&Union::g, u);414 assert(result == 52);415 }416}417 418int main(int, char**) {419 bullet_one_two_tests();420 bullet_three_four_tests();421 bullet_five_tests();422 noexcept_test();423 424 return 0;425}426