/*!
* \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 .
*/
#ifndef __utl_utility_invoke_h__
#define __utl_utility_invoke_h__
#include
#include
#include
#include
#include
/*!
* \ingroup utility
* \defgroup invoke
*/
//! @{
namespace utl {
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 a callable object (for C++14)
template
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
struct is_invocable :
std::is_constructible<
std::function,
std::reference_wrapper::type>
> { };
//! std::is_invocable_r trait for C++11
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<_Callable&&>(), std::declval<_Args&&>()...)
);
};
template
struct invoke_result_ {
using type = meta::nil_;
};
template
struct invoke_result_ {
using type = meta::invoke_t<
meta::quote, _Callable, _Args...
>;
};
}
//! invoke_result (for C++14)
template
using invoke_result = detail::invoke_result_<
is_invocable<_Callable, _Args...>::value,
_Callable,
_Args...
>;
//! invoke_result_t (for C++14)
template
using invoke_result_t = meta::eval <
invoke_result<_Callable, _Args...>
>;
}
//! @}
#endif /* __utl_utility_invoke_h__ */