From: Yedidya Feldblum <yfeldblum@fb.com> Date: Tue, 2 Jan 2018 01:05:00 +0000 (-0800) Subject: invoke and member-invoke tweaks X-Git-Tag: v2018.01.08.00~21 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=1a50cb78590fabf164630808f1be23a9bef6bcc7;p=folly.git invoke and member-invoke tweaks Summary: [Folly] `invoke` and member-`invoke` tweaks. * Direct `static_cast` v.s. `std::forward` is okay. * Implement member-`invoke` in terms of `invoke` and extract most of it to a helper type, minimizing the code directly generated by the preprocessor. Reviewed By: spalamarchuk Differential Revision: D6644119 fbshipit-source-id: e58a83d7ff2dd71b0377d864ef089c34e0239c8d --- diff --git a/folly/functional/Invoke.h b/folly/functional/Invoke.h index 6dce01c0..850c059a 100644 --- a/folly/functional/Invoke.h +++ b/folly/functional/Invoke.h @@ -47,14 +47,14 @@ namespace folly { // mimic: std::invoke, C++17 template <typename F, typename... Args> constexpr auto invoke(F&& f, Args&&... args) noexcept( - noexcept(std::forward<F>(f)(std::forward<Args>(args)...))) - -> decltype(std::forward<F>(f)(std::forward<Args>(args)...)) { - return std::forward<F>(f)(std::forward<Args>(args)...); + noexcept(static_cast<F&&>(f)(static_cast<Args&&>(args)...))) + -> decltype(static_cast<F&&>(f)(static_cast<Args&&>(args)...)) { + return static_cast<F&&>(f)(static_cast<Args&&>(args)...); } template <typename M, typename C, typename... Args> constexpr auto invoke(M(C::*d), Args&&... args) - -> decltype(std::mem_fn(d)(std::forward<Args>(args)...)) { - return std::mem_fn(d)(std::forward<Args>(args)...); + -> decltype(std::mem_fn(d)(static_cast<Args&&>(args)...)) { + return std::mem_fn(d)(static_cast<Args&&>(args)...); } } // namespace folly @@ -162,6 +162,45 @@ struct is_nothrow_invocable_r #endif +namespace folly { +namespace detail { + +template <typename Invoke> +struct member_invoke_proxy { + public: + template <typename O, typename... Args> + struct invoke_result : folly::invoke_result<Invoke, O, Args...> {}; + template <typename O, typename... Args> + using invoke_result_t = folly::invoke_result_t<Invoke, O, Args...>; + template <typename O, typename... Args> + struct is_invocable : folly::is_invocable<Invoke, O, Args...> {}; + template <typename R, typename O, typename... Args> + struct is_invocable_r : folly::is_invocable_r<R, Invoke, O, Args...> {}; + template <typename O, typename... Args> + struct is_nothrow_invocable + : folly::is_nothrow_invocable<Invoke, O, Args...> {}; + template <typename R, typename O, typename... Args> + struct is_nothrow_invocable_r + : folly::is_nothrow_invocable_r<R, Invoke, O, Args...> {}; + + template <typename O, typename... Args> + static constexpr auto invoke(O&& o, Args&&... args) noexcept( + noexcept(folly::invoke( + Invoke{}, + static_cast<O&&>(o), + static_cast<Args&&>(args)...))) + -> decltype(folly::invoke( + Invoke{}, + static_cast<O&&>(o), + static_cast<Args&&>(args)...)) { + return folly::invoke( + Invoke{}, static_cast<O&&>(o), static_cast<Args&&>(args)...); + } +}; + +} // namespace detail +} // namespace folly + /*** * FOLLY_CREATE_MEMBER_INVOKE_TRAITS * @@ -219,72 +258,15 @@ struct is_nothrow_invocable_r * traits::is_nothrow_invocable<int, CanFoo, Car&&>::value // true * traits::is_nothrow_invocable<char*, CanFoo, Car&&>::value // false */ -#define FOLLY_CREATE_MEMBER_INVOKE_TRAITS(classname, membername) \ - struct classname { \ - private: \ - template <typename T> \ - using v_ = ::folly::void_t<T>; \ - template <typename F, typename... Args> \ - using result_ = \ - decltype(::std::declval<F>().membername(::std::declval<Args>()...)); \ - template <typename F, typename... Args> \ - struct nothrow_ : std::integral_constant< \ - bool, \ - noexcept(::std::declval<F>().membername( \ - ::std::declval<Args>()...))> {}; \ - \ - template <typename, typename F, typename... Args> \ - struct invoke_result_ {}; \ - template <typename F, typename... Args> \ - struct invoke_result_<v_<result_<F, Args...>>, F, Args...> { \ - using type = result_<F, Args...>; \ - }; \ - \ - template <typename, typename F, typename... Args> \ - struct is_invocable_ : ::std::false_type {}; \ - template <typename F, typename... Args> \ - struct is_invocable_<v_<result_<F, Args...>>, F, Args...> \ - : ::std::true_type {}; \ - \ - template <typename, typename R, typename F, typename... Args> \ - struct is_invocable_r_ : ::std::false_type {}; \ - template <typename R, typename F, typename... Args> \ - struct is_invocable_r_<v_<result_<F, Args...>>, R, F, Args...> \ - : ::std::is_convertible<result_<F, Args...>, R> {}; \ - \ - template <typename, typename F, typename... Args> \ - struct is_nothrow_invocable_ : ::std::false_type {}; \ - template <typename F, typename... Args> \ - struct is_nothrow_invocable_<v_<result_<F, Args...>>, F, Args...> \ - : nothrow_<F, Args...> {}; \ - \ - template <typename, typename R, typename F, typename... Args> \ - struct is_nothrow_invocable_r_ : ::std::false_type {}; \ - template <typename R, typename F, typename... Args> \ - struct is_nothrow_invocable_r_<v_<result_<F, Args...>>, R, F, Args...> \ - : ::folly::StrictConjunction< \ - ::std::is_convertible<result_<F, Args...>, R>, \ - nothrow_<F, Args...>> {}; \ - \ - public: \ - template <typename F, typename... Args> \ - struct invoke_result : invoke_result_<void, F, Args...> {}; \ - template <typename F, typename... Args> \ - using invoke_result_t = typename invoke_result<F, Args...>::type; \ - template <typename F, typename... Args> \ - struct is_invocable : is_invocable_<void, F, Args...> {}; \ - template <typename R, typename F, typename... Args> \ - struct is_invocable_r : is_invocable_r_<void, R, F, Args...> {}; \ - template <typename F, typename... Args> \ - struct is_nothrow_invocable : is_nothrow_invocable_<void, F, Args...> {}; \ - template <typename R, typename F, typename... Args> \ - struct is_nothrow_invocable_r \ - : is_nothrow_invocable_r_<void, R, F, Args...> {}; \ - \ - template <typename F, typename... Args> \ - static constexpr result_<F, Args...> invoke( \ - F&& f, \ - Args&&... args) noexcept(nothrow_<F, Args...>::value) { \ - return std::forward<F>(f).membername(std::forward<Args>(args)...); \ - } \ - } +#define FOLLY_CREATE_MEMBER_INVOKE_TRAITS(classname, membername) \ + struct classname##__folly_detail_member_invoke { \ + template <typename O, typename... Args> \ + constexpr auto operator()(O&& o, Args&&... args) noexcept(noexcept( \ + static_cast<O&&>(o).membername(static_cast<Args&&>(args)...))) \ + -> decltype( \ + static_cast<O&&>(o).membername(static_cast<Args&&>(args)...)) { \ + return static_cast<O&&>(o).membername(static_cast<Args&&>(args)...); \ + } \ + }; \ + struct classname : ::folly::detail::member_invoke_proxy< \ + classname##__folly_detail_member_invoke> {}