// Copyright (C) 2021 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_INVOKE_Hh_
#define DLIB_INVOKE_Hh_
#include <functional>
#include <type_traits>
#include "utility.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
namespace detail
{
template< typename T >
struct is_reference_wrapper : std::false_type {};
template< typename U >
struct is_reference_wrapper<std::reference_wrapper<U>> : std::true_type {};
template <
typename Base,
typename T,
typename Derived,
typename... Args
>
constexpr auto invoke_(
T Base::*pmf, //pointer to member function
Derived&& ref,
Args&&... args
)
noexcept(noexcept((std::forward<Derived>(ref).*pmf)(std::forward<Args>(args)...)))
-> typename std::enable_if<
std::is_function<T>::value &&
std::is_base_of<Base, typename std::decay<Derived>::type>::value,
decltype((std::forward<Derived>(ref).*pmf)(std::forward<Args>(args)...))
>::type
{
return (std::forward<Derived>(ref).*pmf)(std::forward<Args>(args)...);
}
template<
typename Base,
typename T,
typename RefWrap,
typename... Args
>
constexpr auto invoke_(
T Base::*pmf, //pointer to member function
RefWrap&& ref,
Args&&... args
)
noexcept(noexcept((ref.get().*pmf)(std::forward<Args>(args)...)))
-> typename std::enable_if<
std::is_function<T>::value &&
is_reference_wrapper<typename std::decay<RefWrap>::type>::value,
decltype((ref.get().*pmf)(std::forward<Args>(args)...))>::type
{
return (ref.get().*pmf)(std::forward<Args>(args)...);
}
template<
typename Base,
typename T,
typename Ptr,
typename... Args
>
constexpr auto invoke_(
T Base::*pmf, //pointer to member function
Ptr&& ptr,
Args&&... args
)
noexcept(noexcept(((*std::forward<Ptr>(ptr)).*pmf)( std::forward<Args>( args )...)))
-> typename std::enable_if<
std::is_function<T>::value &&
!is_reference_wrapper<typename std::decay<Ptr>::type>::value &&
!std::is_base_of<Base, typename std::decay<Ptr>::type>::value,
decltype(((*std::forward<Ptr>(ptr)).*pmf)(std::forward<Args>(args)...))>::type
{
return ((*std::forward<Ptr>(ptr)).*pmf)( std::forward<Args>( args )...);
}
template<
typename Base,
typename T,
typename Derived
>
constexpr auto invoke_(
T Base::*pmd, //pointer to member data
Derived&& ref
)
noexcept(noexcept(std::forward<Derived>(ref).*pmd))
-> typename std::enable_if<
std::is_object<T>::value &&
std::is_base_of<Base, typename std::decay<Derived>::type>::value,
decltype(std::forward<Derived>(ref).*pmd)>::type
{
return std::forward<Derived>(ref).*pmd;
}
template<
typename Base,
typename T,
typename RefWrap
>
constexpr auto invoke_(
T Base::*pmd, //pointer to member data
RefWrap&& ref
)
noexcept(noexcept(ref.get().*pmd))
-> typename std::enable_if<
std::is_object<T>::value &&
is_reference_wrapper<typename std::decay<RefWrap>::type>::value,
decltype(ref.get().*pmd)>::type
{
return ref.get().*pmd;
}
template<
typename Base,
typename T,
typename Ptr
>
constexpr auto invoke_(
T Base::*pmd, //pointer to member data
Ptr&& ptr
)
noexcept(noexcept((*std::forward<Ptr>(ptr)).*pmd))
-> typename std::enable_if<
std::is_object<T>::value &&
!is_reference_wrapper<typename std::decay<Ptr>::type>::value &&
!std::is_base_of<Base, typename std::decay<Ptr>::type>::value,
decltype((*std::forward<Ptr>(ptr)).*pmd)>::type
{
return (*std::forward<Ptr>(ptr)).*pmd;
}
template<
typename F,
typename... Args
>
constexpr auto invoke_(
F && f,
Args&&... args
)
noexcept(noexcept(std::forward<F>( f )( std::forward<Args>( args )...)))
-> typename std::enable_if<
!std::is_member_pointer<typename std::decay<F>::type>::value,
decltype(std::forward<F>(f)(std::forward<Args>(args)...))>::type
{
return std::forward<F>( f )( std::forward<Args>( args )...);
}
} // end namespace detail
// ----------------------------------------------------------------------------------------
template< typename F, typename... Args>
constexpr auto invoke(F && f, Args &&... args)
/*!
ensures
- identical to std::invoke(std::forward<F>(f), std::forward<Args>(args)...)
- works with C++11 onwards
!*/
noexcept(noexcept(detail::invoke_(std::forward<F>( f ), std::forward<Args>( args )...)))
-> decltype(detail::invoke_(std::forward<F>( f ), std::forward<Args>( args )...))
{
return detail::invoke_(std::forward<F>( f ), std::forward<Args>( args )...);
}
// ----------------------------------------------------------------------------------------
namespace detail
{
template< typename AlwaysVoid, typename, typename...>
struct invoke_traits
{
static constexpr bool value = false;
};
template< typename F, typename... Args >
struct invoke_traits< decltype( void(dlib::invoke(std::declval<F>(), std::declval<Args>()...)) ), F, Args...>
{
static constexpr bool value = true;
using type = decltype( dlib::invoke(std::declval<F>(), std::declval<Args>()...) );
};
} // end namespace detail
// ----------------------------------------------------------------------------------------
template< typename F, typename... Args >
struct invoke_result : detail::invoke_traits< void, F, Args...> {};
/*!
ensures
- identical to std::invoke_result<F, Args..>
- works with C++11 onwards
!*/
template< typename F, typename... Args >
using invoke_result_t = typename invoke_result<F, Args...>::type;
/*!
ensures
- identical to std::invoke_result_t<F, Args..>
- works with C++11 onwards
!*/
// ----------------------------------------------------------------------------------------
template< typename F, typename... Args >
struct is_invocable : std::integral_constant<bool, detail::invoke_traits< void, F, Args...>::value> {};
/*!
ensures
- identical to std::is_invocable<F, Args..>
- works with C++11 onwards
!*/
// ----------------------------------------------------------------------------------------
template <typename R, typename F, typename... Args>
struct is_invocable_r : std::integral_constant<bool, dlib::is_invocable<F, Args...>::value &&
std::is_convertible<invoke_result_t<F, Args...>, R>::value> {};
/*!
ensures
- identical to std::is_invocable_r<R, F, Args..>
- works with C++11 onwards
!*/
// ----------------------------------------------------------------------------------------
template< typename R, typename F, typename... Args>
constexpr typename std::enable_if<dlib::is_invocable_r<R, F, Args...>::value, R>::type
invoke_r(F && f, Args &&... args)
/*!
ensures
- identical to std::invoke_r<R>(std::forward<F>(f), std::forward<Args>(args)...)
- works with C++11 onwards
!*/
noexcept(noexcept(dlib::invoke(std::forward<F>( f ), std::forward<Args>( args )...)))
{
return dlib::invoke(std::forward<F>( f ), std::forward<Args>( args )...);
}
// ----------------------------------------------------------------------------------------
namespace detail
{
template<typename F, typename Tuple, std::size_t... I>
constexpr auto apply_impl(F&& fn, Tuple&& tpl, index_sequence<I...>)
noexcept(noexcept(dlib::invoke(std::forward<F>(fn),
std::get<I>(std::forward<Tuple>(tpl))...)))
-> decltype(dlib::invoke(std::forward<F>(fn),
std::get<I>(std::forward<Tuple>(tpl))...))
{
return dlib::invoke(std::forward<F>(fn),
std::get<I>(std::forward<Tuple>(tpl))...);
}
} // end namespace detail
// ----------------------------------------------------------------------------------------
template<typename F, typename Tuple>
constexpr auto apply(F&& fn, Tuple&& tpl)
/*!
ensures
- identical to std::apply(std::forward<F>(f), std::forward<Tuple>(tpl))
- works with C++11 onwards
!*/
noexcept(noexcept(detail::apply_impl(std::forward<F>(fn),
std::forward<Tuple>(tpl),
make_index_sequence<std::tuple_size<typename std::remove_reference<Tuple>::type >::value>{})))
-> decltype(detail::apply_impl(std::forward<F>(fn),
std::forward<Tuple>(tpl),
make_index_sequence<std::tuple_size<typename std::remove_reference<Tuple>::type >::value>{}))
{
return detail::apply_impl(std::forward<F>(fn),
std::forward<Tuple>(tpl),
make_index_sequence<std::tuple_size<typename std::remove_reference<Tuple>::type >::value>{});
}
// ----------------------------------------------------------------------------------------
namespace detail
{
template <class T, class Tuple, std::size_t... I>
constexpr T make_from_tuple_impl( Tuple&& t, index_sequence<I...> )
{
return T(std::get<I>(std::forward<Tuple>(t))...);
}
} // end namespace detail
// ----------------------------------------------------------------------------------------
template <class T, class Tuple>
constexpr T make_from_tuple( Tuple&& t )
/*!
ensures
- identical to std::make_from_tuple<T>(std::forward<Tuple>(t))
- works with C++11 onwards
!*/
{
return detail::make_from_tuple_impl<T>(std::forward<Tuple>(t),
make_index_sequence<std::tuple_size<typename std::remove_reference<Tuple>::type >::value>{});
}
// ----------------------------------------------------------------------------------------
}
#endif //DLIB_INVOKE_Hh_