|
- /*!
- * \file utl/utility/invoke.h
- * \brief invoke() and invoke traits implementation
- */
- #ifndef __utl_utility_invoke_h__
- #define __utl_utility_invoke_h__
-
- #include <utl/core/impl.h>
- #include <utl/meta/meta.h>
-
- #include <type_traits>
- #include <functional>
- #include <utility>
-
- //! \defgroup utility Utility
-
- /*!
- * \ingroup utility
- * \defgroup util_invoke Invoke
- */
- //! @{
- namespace utl {
-
- #if !defined __cpp_lib_is_invocable
- namespace detail {
-
- template <class T>
- struct is_ref_wrapper : meta::false_ {};
- template <class U>
- struct is_ref_wrapper<std::reference_wrapper<U>> : meta::true_ {};
-
- // 1
- template <class T, class Type, class T1, class... Args,
- meta::enable_if_t<
- std::is_member_function_pointer<std::decay_t<Type T::*>>::value &&
- std::is_base_of<T, std::decay_t<T1>>::value,
- int> =0
- >
- decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) {
- return (std::forward<T1>(t1).*f)(std::forward<Args>(args)...);
- }
-
- // 2
- template <class T, class Type, class T1, class... Args,
- meta::enable_if_t<
- std::is_member_function_pointer<std::decay_t<Type T::*>>::value &&
- is_ref_wrapper<std::decay_t<T1>>::value,
- int> =0
- >
- decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) {
- return (t1.get().*f)(std::forward<Args>(args)...);
- }
-
- // 3
- template <class T, class Type, class T1, class... Args,
- meta::enable_if_t<
- std::is_member_function_pointer<std::decay_t<Type T::*>>::value &&
- !std::is_base_of<T, std::decay_t<T1>>::value &&
- !is_ref_wrapper<std::decay_t<T1>>::value,
- int> =0
- >
- decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) {
- return ((*std::forward<T1>(t1)).*f)(std::forward<Args>(args)...);
- }
-
- // 4
- template <class T, class Type, class T1, class... Args,
- meta::enable_if_t<
- std::is_member_object_pointer<std::decay_t<Type T::*>>::value &&
- std::is_base_of<T, std::decay_t<T1>>::value,
- int> =0
- >
- decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) {
- return std::forward<T1>(t1).*f;
- }
-
- // 5
- template <class T, class Type, class T1, class... Args,
- meta::enable_if_t<
- std::is_member_object_pointer<std::decay_t<Type T::*>>::value &&
- is_ref_wrapper<std::decay_t<T1>>::value,
- int> =0
- >
- decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) {
- return t1.get().*f;
- }
-
- // 6
- template <class T, class Type, class T1, class... Args,
- meta::enable_if_t<
- std::is_member_object_pointer<std::decay_t<Type T::*>>::value &&
- !std::is_base_of<T, std::decay_t<T1>>::value &&
- !is_ref_wrapper<std::decay_t<T1>>::value,
- int> =0
- >
- decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) {
- return (*std::forward<T1>(t1)).*f;
- }
-
- template <class F, class... Args>
- decltype(auto) invoke_impl_(F&& f, Args&&... args) {
- return std::forward<F>(f)(std::forward<Args>(args)...);
- }
-
- } // namespace detail
-
- //! Invoke the Callable object \c fn with the parameters args.
- //! As by INVOKE(std::forward<F>(f), std::forward<Args>(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<typename Callable, typename... Args>
- inline decltype(auto) invoke(Callable&& fn, Args&&... args) {
- return detail::invoke_impl_(
- std::forward<Callable>(fn), std::forward<Args>(args)...
- );
- }
-
- //!
- //! \brief
- //! Determines whether \c F can be invoked with the arguments \c Args....
- //!
- //! Formally, determines whether invoke(declval<Fn>(), declval<ArgTypes>()...)
- //! 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 <typename F, typename... Args>
- struct is_invocable :
- std::is_constructible<
- std::function<void(Args ...)>,
- std::reference_wrapper<typename std::remove_reference<F>::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<Fn>(), declval<ArgTypes>()...)
- //! 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 <typename R, typename F, typename... Args>
- struct is_invocable_r :
- std::is_constructible<
- std::function<R(Args ...)>,
- std::reference_wrapper<typename std::remove_reference<F>::type>
- > { };
-
- /*!
- * invoke_result (SFINAE friendly)
- */
- //! @{
- namespace detail {
- template<typename Callable, typename... Args>
- struct try_invoke {
- using type = decltype (
- detail::invoke_impl_(std::declval<Callable&&>(), std::declval<Args&&>()...)
- );
- };
-
- template<bool B, typename Callable, typename... Args>
- struct invoke_result_ {
- using type = meta::nil_;
- };
-
- template <typename Callable, typename... Args>
- struct invoke_result_ <true, Callable, Args...> {
- using type = meta::invoke_t<
- meta::quote<try_invoke>, 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 <typename Callable, typename... Args>
- using invoke_result = detail::invoke_result_<
- is_invocable<Callable, Args...>::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<typename Callable, typename... Args>
- using invoke_result_t = meta::eval <
- invoke_result<Callable, Args...>
- >;
- //! @}
-
- #else
-
- #endif
- }
-
- //! @}
-
-
- #endif /* __utl_utility_invoke_h__ */
|