/*! * \file utl/utility/invoke.h * \brief invoke() and invoke traits implementation */ #ifndef __utl_utility_invoke_h__ #define __utl_utility_invoke_h__ #include #include #include #include #include //! \defgroup utility Utility /*! * \ingroup utility * \defgroup util_invoke Invoke */ //! @{ namespace utl { #if !defined __cpp_lib_is_invocable namespace detail { template struct is_ref_wrapper : meta::false_ {}; template struct is_ref_wrapper> : meta::true_ {}; // 1 template >::value && std::is_base_of>::value, int> =0 > decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) { return (std::forward(t1).*f)(std::forward(args)...); } // 2 template >::value && is_ref_wrapper>::value, int> =0 > decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) { return (t1.get().*f)(std::forward(args)...); } // 3 template >::value && !std::is_base_of>::value && !is_ref_wrapper>::value, int> =0 > decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) { return ((*std::forward(t1)).*f)(std::forward(args)...); } // 4 template >::value && std::is_base_of>::value, int> =0 > decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) { return std::forward(t1).*f; } // 5 template >::value && is_ref_wrapper>::value, int> =0 > decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) { return t1.get().*f; } // 6 template >::value && !std::is_base_of>::value && !is_ref_wrapper>::value, int> =0 > decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) { return (*std::forward(t1)).*f; } template decltype(auto) invoke_impl_(F&& f, Args&&... args) { return std::forward(f)(std::forward(args)...); } } // namespace detail //! Invoke the Callable object \c fn with the parameters args. //! As by INVOKE(std::forward(f), std::forward(args)...). //! //! \note //! This implementation fills the lack of an invoke() utility for builds //! pre-c++17. //! //! \param fn Callable object to be invoked //! \param args Arguments to pass to \c fn //! \return The return of the Callable underling functionality //! template inline decltype(auto) invoke(Callable&& fn, Args&&... args) { return detail::invoke_impl_( std::forward(fn), std::forward(args)... ); } //! //! \brief //! Determines whether \c F can be invoked with the arguments \c Args.... //! //! Formally, determines whether invoke(declval(), declval()...) //! is well formed when treated as an unevaluated operand, //! where invoke is \c Callable. //! //! \note //! This implementation fills the lack of an invoke() utility for builds //! pre-c++17. //! //! \tparam F The candidate type to check if its invocable //! \tparam Args The arguments for the call //! \return If \c F is invocable //! \arg true Is invocable //! \arg false Is not invocable template struct is_invocable : std::is_constructible< std::function, std::reference_wrapper::type> > { }; //! \brief //! Determines whether \c F can be invoked with the arguments \c Args... //! to yield a result that is convertible to \c R. //! //! Formally, determines whether invoke(declval(), declval()...) //! is well formed when treated as an unevaluated operand, where invoke is \c Callable. //! //! \tparam R The return type of invocable functionality //! \tparam F The candidate type to check if its invocable //! \tparam Args The arguments to pass to \c F //! \return If \c F is invocable //! \arg true Is invocable //! \arg false Is not invocable template struct is_invocable_r : std::is_constructible< std::function, std::reference_wrapper::type> > { }; /*! * invoke_result (SFINAE friendly) */ //! @{ namespace detail { template struct try_invoke { using type = decltype ( detail::invoke_impl_(std::declval(), std::declval()...) ); }; template struct invoke_result_ { using type = meta::nil_; }; template struct invoke_result_ { using type = meta::invoke_t< meta::quote, Callable, Args... >; }; } //! trait that deduces the return type of an INVOKE expression at compile time. //! //! \tparam Callable The candidate type to check if its invocable //! \tparam Args The arguments to pass to \c F //! //! \b member \n //! \::type The return type of the \c Callable type if invoked with the arguments Args.... template using invoke_result = detail::invoke_result_< is_invocable::value, Callable, Args... >; //! trait that deduces the return type of an INVOKE expression at compile time. //! //! \tparam Callable The candidate type to check if its invocable //! \tparam Args The arguments to pass to \c F //! //! \return The type of the \c Callable type if invoked with the arguments Args.... template using invoke_result_t = meta::eval < invoke_result >; //! @} #else #endif } //! @} #endif /* __utl_utility_invoke_h__ */