187 lines
6.0 KiB
C++
187 lines
6.0 KiB
C++
/*!
|
|
* \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__ */
|