/* * Copyright 2017-present Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include /** * include or backport: * * std::invoke * * std::invoke_result * * std::invoke_result_t * * std::is_invocable * * std::is_invocable_r * * std::is_nothrow_invocable * * std::is_nothrow_invocable_r */ #if __cpp_lib_invoke >= 201411 || _MSC_VER namespace folly { /* using override */ using std::invoke; } #else namespace folly { // mimic: std::invoke, C++17 template constexpr auto invoke(F&& f, Args&&... args) noexcept( noexcept(static_cast(f)(static_cast(args)...))) -> decltype(static_cast(f)(static_cast(args)...)) { return static_cast(f)(static_cast(args)...); } template constexpr auto invoke(M(C::*d), Args&&... args) -> decltype(std::mem_fn(d)(static_cast(args)...)) { return std::mem_fn(d)(static_cast(args)...); } } // namespace folly #endif // Only available in >= MSVC 2017 15.3 in C++17 #if __cpp_lib_is_invocable >= 201703 || \ (_MSC_VER >= 1911 && _MSVC_LANG > 201402) namespace folly { /* using override */ using std::invoke_result; /* using override */ using std::invoke_result_t; /* using override */ using std::is_invocable; /* using override */ using std::is_invocable_r; /* using override */ using std::is_nothrow_invocable; /* using override */ using std::is_nothrow_invocable_r; } // namespace folly #else namespace folly { namespace invoke_detail { template using invoke_result_ = decltype(invoke(std::declval(), std::declval()...)); template struct invoke_nothrow_ : bool_constant(), std::declval()...))> {}; // from: http://en.cppreference.com/w/cpp/types/result_of, CC-BY-SA template struct invoke_result {}; template struct invoke_result>, F, Args...> { using type = invoke_result_; }; template struct is_invocable : std::false_type {}; template struct is_invocable>, F, Args...> : std::true_type {}; template struct is_invocable_r : std::false_type {}; template struct is_invocable_r>, R, F, Args...> : std::is_convertible, R> {}; template struct is_nothrow_invocable : std::false_type {}; template struct is_nothrow_invocable>, F, Args...> : invoke_nothrow_ {}; template struct is_nothrow_invocable_r : std::false_type {}; template struct is_nothrow_invocable_r>, R, F, Args...> : StrictConjunction< std::is_convertible, R>, invoke_nothrow_> {}; } // namespace invoke_detail // mimic: std::invoke_result, C++17 template struct invoke_result : invoke_detail::invoke_result {}; // mimic: std::invoke_result_t, C++17 template using invoke_result_t = typename invoke_result::type; // mimic: std::is_invocable, C++17 template struct is_invocable : invoke_detail::is_invocable {}; // mimic: std::is_invocable_r, C++17 template struct is_invocable_r : invoke_detail::is_invocable_r {}; // mimic: std::is_nothrow_invocable, C++17 template struct is_nothrow_invocable : invoke_detail::is_nothrow_invocable {}; // mimic: std::is_nothrow_invocable_r, C++17 template struct is_nothrow_invocable_r : invoke_detail::is_nothrow_invocable_r {}; } // namespace folly #endif namespace folly { namespace detail { struct invoke_private_overload; template struct free_invoke_proxy { public: template struct invoke_result : folly::invoke_result {}; template using invoke_result_t = folly::invoke_result_t; template struct is_invocable : folly::is_invocable {}; template struct is_invocable_r : folly::is_invocable_r {}; template struct is_nothrow_invocable : folly::is_nothrow_invocable {}; template struct is_nothrow_invocable_r : folly::is_nothrow_invocable_r {}; template static constexpr auto invoke(Args&&... args) noexcept( noexcept(Invoke{}(static_cast(args)...))) -> decltype(Invoke{}(static_cast(args)...)) { return Invoke{}(static_cast(args)...); } using invoke_type = Invoke; }; } // namespace detail } // namespace folly /*** * FOLLY_CREATE_FREE_INVOKE_TRAITS * * Used to create traits container, bound to a specific free-invocable name, * with the following member traits types and aliases: * * * invoke_result * * invoke_result_t * * is_invocable * * is_invocable_r * * is_nothrow_invocable * * is_nothrow_invocable_r * * The container also has a static member function: * * * invoke * * And a member type alias: * * * invoke_type * * These members have behavior matching the behavior of C++17's corresponding * invocation traits types, aliases, and functions, but substituting canonical * invocation with member invocation. * * Example: * * FOLLY_CREATE_FREE_INVOKE_TRAITS(foo_invoke_traits, foo); * * The traits container type `foo_invoke_traits` is generated in the current * namespace and has the listed member types and aliases. They may be used as * follows: * * namespace Deep { * struct CanFoo {}; * int foo(CanFoo const&, Bar&) { return 1; } * int foo(CanFoo&&, Car&&) noexcept { return 2; } * } * * using traits = foo_invoke_traits; * * traits::invoke(Deep::CanFoo{}, Car{}) // 2 * * traits::invoke_result // has member * traits::invoke_result_t // int * traits::invoke_result // empty * traits::invoke_result_t // error * * traits::is_invocable::value // true * traits::is_invocable::value // false * * traits::is_invocable_r::value // true * traits::is_invocable_r::value // false * * traits::is_nothrow_invocable::value // false * traits::is_nothrow_invocable::value // true * * traits::is_nothrow_invocable::value // false * traits::is_nothrow_invocable::value // false * traits::is_nothrow_invocable::value // true * traits::is_nothrow_invocable::value // false * * When a name has a primary definition in a fixed namespace and alternate * definitions in the namespaces of its arguments, the primary definition may * automatically be found as follows: * * FOLLY_CREATE_FREE_INVOKE_TRAITS(swap_invoke_traits, swap, std); * * In this case, `swap_invoke_traits::invoke(int&, int&)` will use the primary * definition found in `namespace std` relative to the current namespace, which * may be equivalent to `namespace ::std`. In contrast: * * namespace Deep { * struct HasData {}; * void swap(HasData&, HasData&) { throw 7; } * } * * using traits = swap_invoke_traits; * * HasData a, b; * traits::invoke(a, b); // throw 7 */ #define FOLLY_CREATE_FREE_INVOKE_TRAITS(classname, funcname, ...) \ namespace classname##__folly_detail_invoke_ns { \ namespace classname##__folly_detail_invoke_ns_inline { \ FOLLY_PUSH_WARNING \ FOLLY_CLANG_DISABLE_WARNING("-Wunused-function") \ void funcname(::folly::detail::invoke_private_overload&); \ FOLLY_POP_WARNING \ } \ using FB_ARG_2_OR_1( \ classname##__folly_detail_invoke_ns_inline \ FOLLY_PP_DETAIL_APPEND_VA_ARG(__VA_ARGS__))::funcname; \ struct classname##__folly_detail_invoke { \ template \ constexpr auto operator()(Args&&... args) const \ noexcept(noexcept(funcname(static_cast(args)...))) \ -> decltype(funcname(static_cast(args)...)) { \ return funcname(static_cast(args)...); \ } \ }; \ } \ struct classname : ::folly::detail::free_invoke_proxy< \ classname##__folly_detail_invoke_ns:: \ classname##__folly_detail_invoke> {} namespace folly { namespace detail { template struct member_invoke_proxy { public: template struct invoke_result : folly::invoke_result {}; template using invoke_result_t = folly::invoke_result_t; template struct is_invocable : folly::is_invocable {}; template struct is_invocable_r : folly::is_invocable_r {}; template struct is_nothrow_invocable : folly::is_nothrow_invocable {}; template struct is_nothrow_invocable_r : folly::is_nothrow_invocable_r {}; template static constexpr auto invoke(O&& o, Args&&... args) noexcept( noexcept(Invoke{}(static_cast(o), static_cast(args)...))) -> decltype(Invoke{}(static_cast(o), static_cast(args)...)) { return Invoke{}(static_cast(o), static_cast(args)...); } using invoke_type = Invoke; }; } // namespace detail } // namespace folly /*** * FOLLY_CREATE_MEMBER_INVOKE_TRAITS * * Used to create traits container, bound to a specific member-invocable name, * with the following member traits types and aliases: * * * invoke_result * * invoke_result_t * * is_invocable * * is_invocable_r * * is_nothrow_invocable * * is_nothrow_invocable_r * * The container also has a static member function: * * * invoke * * And a member type alias: * * * invoke_type * * These members have behavior matching the behavior of C++17's corresponding * invocation traits types, aliases, and functions, but substituting canonical * invocation with member invocation. * * Example: * * FOLLY_CREATE_MEMBER_INVOKE_TRAITS(foo_invoke_traits, foo); * * The traits container type `foo_invoke_traits` is generated in the current * namespace and has the listed member types and aliases. They may be used as * follows: * * struct CanFoo { * int foo(Bar&) { return 1; } * int foo(Car&&) noexcept { return 2; } * }; * * using traits = foo_invoke_traits; * * traits::invoke(CanFoo{}, Car{}) // 2 * * traits::invoke_result // has member * traits::invoke_result_t // int * traits::invoke_result // empty * traits::invoke_result_t // error * * traits::is_invocable::value // true * traits::is_invocable::value // false * * traits::is_invocable_r::value // true * traits::is_invocable_r::value // false * * traits::is_nothrow_invocable::value // false * traits::is_nothrow_invocable::value // true * * traits::is_nothrow_invocable::value // false * traits::is_nothrow_invocable::value // false * traits::is_nothrow_invocable::value // true * traits::is_nothrow_invocable::value // false */ #define FOLLY_CREATE_MEMBER_INVOKE_TRAITS(classname, membername) \ struct classname##__folly_detail_member_invoke { \ template \ constexpr auto operator()(O&& o, Args&&... args) const noexcept(noexcept( \ static_cast(o).membername(static_cast(args)...))) \ -> decltype( \ static_cast(o).membername(static_cast(args)...)) { \ return static_cast(o).membername(static_cast(args)...); \ } \ }; \ struct classname : ::folly::detail::member_invoke_proxy< \ classname##__folly_detail_member_invoke> {}