/// \file // Range v3 library // // Copyright Eric Niebler 2013-present // Copyright Casey Carter 2016 // // Use, modification and distribution is subject to the // Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // Project home: https://github.com/ericniebler/range-v3 // #ifndef RANGES_V3_FUNCTIONAL_INVOKE_HPP #define RANGES_V3_FUNCTIONAL_INVOKE_HPP #include <functional> #include <type_traits> #include <meta/meta.hpp> #include <concepts/concepts.hpp> #include <range/v3/range_fwd.hpp> #include <range/v3/utility/static_const.hpp> RANGES_DIAGNOSTIC_PUSH RANGES_DIAGNOSTIC_IGNORE_CXX17_COMPAT RANGES_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS #ifndef RANGES_CONSTEXPR_INVOKE #ifdef RANGES_WORKAROUND_CLANG_23135 #define RANGES_CONSTEXPR_INVOKE 0 #else #define RANGES_CONSTEXPR_INVOKE 1 #endif #endif namespace ranges { /// \addtogroup group-functional /// @{ /// \cond namespace detail { template<typename U> U & can_reference_(U &&); // clang-format off CPP_def ( template(typename T) concept dereferenceable_, requires (T &&t) ( detail::can_reference_(*static_cast<T &&>(t)) ) ); // clang-format on template<class T> RANGES_INLINE_VAR constexpr bool is_reference_wrapper_v = meta::is<T, reference_wrapper>::value || meta::is<T, std::reference_wrapper>::value; } // namespace detail /// \endcond template<class T> RANGES_INLINE_VAR constexpr bool is_reference_wrapper_v = detail::is_reference_wrapper_v<detail::decay_t<T>>; template<typename T> using is_reference_wrapper = meta::bool_<is_reference_wrapper_v<T>>; template<typename T> using is_reference_wrapper_t RANGES_DEPRECATED( "is_reference_wrapper_t is deprecated.") = meta::_t<is_reference_wrapper<T>>; struct invoke_fn { private: template<class, class T1> constexpr static decltype(auto) CPP_fun(coerce)(T1 && t1, long)( // noexcept(noexcept(*static_cast<T1 &&>(t1))) // requires detail::dereferenceable_<T1>) { return *static_cast<T1 &&>(t1); } template<class T, class T1> constexpr static auto coerce(T1 && t1, int) noexcept -> CPP_ret(T1 &&)( // requires derived_from<detail::decay_t<T1>, T>) { return static_cast<T1 &&>(t1); } template<class, class T1> constexpr static decltype(auto) CPP_fun(coerce)(T1 && t1, int)( noexcept(true) // requires detail::is_reference_wrapper_v<detail::decay_t<T1>>) { return static_cast<T1 &&>(t1).get(); } public: // clang-format off template<class F, class T, class T1, class... Args> constexpr auto CPP_auto_fun(operator())(F T::*f, T1&& t1, Args&&... args)(const) ( return (invoke_fn::coerce<T>(static_cast<T1&&>(t1), 0).*f) (static_cast<Args&&>(args)...) ) template<class D, class T, class T1> constexpr auto CPP_auto_fun(operator())(D T::*f, T1&& t1)(const) ( return invoke_fn::coerce<T>(static_cast<T1&&>(t1), 0).*f ) template<class F, class... Args> CPP_PP_IIF(RANGES_CONSTEXPR_INVOKE)(CPP_PP_EXPAND, CPP_PP_EAT)(constexpr) auto CPP_auto_fun(operator())(F&& f, Args&&... args)(const) ( return static_cast<F&&>(f)(static_cast<Args&&>(args)...) ) // clang-format on }; RANGES_INLINE_VARIABLE(invoke_fn, invoke) #ifdef RANGES_WORKAROUND_MSVC_701385 /// \cond namespace detail { template<typename Void, typename Fun, typename... Args> struct _invoke_result_ {}; template<typename Fun, typename... Args> struct _invoke_result_< meta::void_<decltype(invoke(std::declval<Fun>(), std::declval<Args>()...))>, Fun, Args...> { using type = decltype(invoke(std::declval<Fun>(), std::declval<Args>()...)); }; } // namespace detail /// \endcond template<typename Fun, typename... Args> using invoke_result = detail::_invoke_result_<void, Fun, Args...>; template<typename Fun, typename... Args> using invoke_result_t = meta::_t<invoke_result<Fun, Args...>>; #else // RANGES_WORKAROUND_MSVC_701385 template<typename Fun, typename... Args> using invoke_result_t = decltype(invoke(std::declval<Fun>(), std::declval<Args>()...)); template<typename Fun, typename... Args> struct invoke_result : meta::defer<invoke_result_t, Fun, Args...> {}; #endif // RANGES_WORKAROUND_MSVC_701385 /// \cond namespace detail { template<bool IsInvocable> struct is_nothrow_invocable_impl_ { template<typename Fn, typename... Args> static constexpr bool apply() noexcept { return false; } }; template<> struct is_nothrow_invocable_impl_<true> { template<typename Fn, typename... Args> static constexpr bool apply() noexcept { return noexcept(invoke(std::declval<Fn>(), std::declval<Args>()...)); } }; } // namespace detail /// \endcond template<typename Fn, typename... Args> RANGES_INLINE_VAR constexpr bool is_invocable_v = meta::is_trait<invoke_result<Fn, Args...>>::value; template<typename Fn, typename... Args> RANGES_INLINE_VAR constexpr bool is_nothrow_invocable_v = detail::is_nothrow_invocable_impl_<is_invocable_v<Fn, Args...>>::template apply< Fn, Args...>(); /// \cond template<typename Sig> struct RANGES_DEPRECATED( "ranges::result_of is deprecated. " "Please use ranges::invoke_result") result_of {}; template<typename Fun, typename... Args> struct RANGES_DEPRECATED( "ranges::result_of is deprecated. " "Please use ranges::invoke_result") result_of<Fun(Args...)> : meta::defer<invoke_result_t, Fun, Args...> {}; /// \endcond namespace cpp20 { using ranges::invoke; using ranges::invoke_result; using ranges::invoke_result_t; using ranges::is_invocable_v; using ranges::is_nothrow_invocable_v; } // namespace cpp20 /// @} } // namespace ranges RANGES_DIAGNOSTIC_POP #endif // RANGES_V3_FUNCTIONAL_INVOKE_HPP