|
- /*!
- * \file utl/utility/invoke.h
- * \brief invoke() and invoke() traits implementation
- *
- * Copyright (C) 2018-2019 Christos Choutouridis
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more detail.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #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>
-
- /*!
- * \ingroup utility
- * \defgroup invoke
- *
- */
- //! @{
- namespace utl {
-
- 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 a callable object (for C++14)
- 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)...
- );
- }
- //! @}
-
- //! std::is_invocable trait for C++11
- template <typename F, typename... Args>
- struct is_invocable :
- std::is_constructible<
- std::function<void(Args ...)>,
- std::reference_wrapper<typename std::remove_reference<F>::type>
- > { };
-
- //! std::is_invocable_r trait for C++11
- 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...
- >;
- };
- }
- //! invoke_result (for C++14)
- template <typename _Callable, typename... _Args>
- using invoke_result = detail::invoke_result_<
- is_invocable<_Callable, _Args...>::value,
- _Callable,
- _Args...
- >;
-
- //! invoke_result_t (for C++14)
- template<typename _Callable, typename... _Args>
- using invoke_result_t = meta::eval <
- invoke_result<_Callable, _Args...>
- >;
- }
-
- //! @}
-
-
- #endif /* __utl_utility_invoke_h__ */
|