mirror of
https://github.com/davisking/dlib.git
synced 2024-11-01 10:14:53 +08:00
Added bind_front() and bind_back() (#2705)
* Added bind_front() * - Added bind_back() - moved contents of invoke.h into functional.h - invoke.h just includes functional.h - added tests * though it doesn't make a difference, use correct header * add docs * Give this a try. Might make gcc7 happy * workaround for gcc7 bug Co-authored-by: pf <pf@me> Co-authored-by: Davis King <davis@dlib.net>
This commit is contained in:
parent
1ce7b9cbc5
commit
b9ac468169
@ -4,7 +4,7 @@
|
||||
#define DLIB_AnY_FUNCTION_Hh_
|
||||
|
||||
#include "../assert.h"
|
||||
#include "../invoke.h"
|
||||
#include "../functional.h"
|
||||
#include "any.h"
|
||||
#include "any_function_abstract.h"
|
||||
|
||||
|
398
dlib/functional.h
Normal file
398
dlib/functional.h
Normal file
@ -0,0 +1,398 @@
|
||||
// Copyright (C) 2021 Davis E. King (davis@dlib.net)
|
||||
// License: Boost Software License See LICENSE.txt for the full license.
|
||||
#ifndef DLIB_FUNCTIONAL_Hh_
|
||||
#define DLIB_FUNCTIONAL_Hh_
|
||||
|
||||
#include <functional>
|
||||
#include "type_traits.h"
|
||||
#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
|
||||
!*/
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <class, typename R, typename F, typename... Args>
|
||||
struct is_invocable_r_impl : std::false_type {};
|
||||
|
||||
template <typename R, typename F, typename... Args>
|
||||
struct is_invocable_r_impl<dlib::void_t<std::is_convertible<invoke_result_t<F, Args...>, R>>, R, F, Args...> : std::true_type {};
|
||||
}
|
||||
|
||||
template <typename R, typename F, typename... Args>
|
||||
struct is_invocable_r : detail::is_invocable_r_impl<void, R, F, Args...> {};
|
||||
/*!
|
||||
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>{});
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<class Binder, std::size_t ...I, class ...Rest>
|
||||
constexpr static auto binder_run(
|
||||
Binder&& self,
|
||||
std::integral_constant<bool, false>,
|
||||
index_sequence<I...>,
|
||||
Rest&&... rest
|
||||
) noexcept(noexcept(dlib::invoke(std::forward<Binder>(self).func, std::get<I>(std::forward<Binder>(self).args)..., std::forward<Rest>(rest)...)))
|
||||
-> decltype(dlib::invoke(std::forward<Binder>(self).func, std::get<I>(std::forward<Binder>(self).args)..., std::forward<Rest>(rest)...))
|
||||
{
|
||||
return dlib::invoke(std::forward<Binder>(self).func, std::get<I>(std::forward<Binder>(self).args)..., std::forward<Rest>(rest)...);
|
||||
}
|
||||
|
||||
template<class Binder, std::size_t ...I, class ...Rest>
|
||||
constexpr static auto binder_run(
|
||||
Binder&& self,
|
||||
std::integral_constant<bool, true>,
|
||||
index_sequence<I...>,
|
||||
Rest&&... rest
|
||||
) noexcept(noexcept(dlib::invoke(std::forward<Binder>(self).func, std::forward<Rest>(rest)..., std::get<I>(std::forward<Binder>(self).args)...)))
|
||||
-> decltype(dlib::invoke(std::forward<Binder>(self).func, std::forward<Rest>(rest)..., std::get<I>(std::forward<Binder>(self).args)...))
|
||||
{
|
||||
return dlib::invoke(std::forward<Binder>(self).func, std::forward<Rest>(rest)..., std::get<I>(std::forward<Binder>(self).args)...);
|
||||
}
|
||||
|
||||
template<bool Back, class F, class ...Args>
|
||||
struct binder_wrapper
|
||||
{
|
||||
F func;
|
||||
std::tuple<Args...> args;
|
||||
|
||||
template<class ...Rest>
|
||||
constexpr auto operator()(Rest&&... rest)
|
||||
noexcept(noexcept(binder_run(std::declval<binder_wrapper&>(), std::integral_constant<bool, Back>{}, index_sequence_for<Args...>{}, std::forward<Rest>(rest)...)))
|
||||
-> decltype(binder_run(std::declval<binder_wrapper&>(), std::integral_constant<bool, Back>{}, index_sequence_for<Args...>{}, std::forward<Rest>(rest)...))
|
||||
{
|
||||
return binder_run(*this, std::integral_constant<bool, Back>{}, index_sequence_for<Args...>{}, std::forward<Rest>(rest)...);
|
||||
}
|
||||
};
|
||||
|
||||
template<bool Back, class F, class... Args>
|
||||
constexpr auto make_binder(
|
||||
F&& func,
|
||||
Args&&... args
|
||||
)
|
||||
{
|
||||
return binder_wrapper<Back, std::decay_t<F>, std::decay_t<Args>...>{std::forward<F>(func), std::forward<Args>(args)...};
|
||||
}
|
||||
}
|
||||
|
||||
template<class F, class ...Args>
|
||||
constexpr auto bind_front(
|
||||
F&& func,
|
||||
Args&&... args
|
||||
) noexcept(noexcept(detail::make_binder<false>(std::forward<F>(func), std::forward<Args>(args)...)))
|
||||
/*!
|
||||
ensures
|
||||
- identical to std::bind_front()
|
||||
- works with C++11 onwards
|
||||
!*/
|
||||
{
|
||||
return detail::make_binder<false>(std::forward<F>(func), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<class F, class ...Args>
|
||||
constexpr auto bind_back(
|
||||
F&& func,
|
||||
Args&&... args
|
||||
) noexcept(noexcept(detail::make_binder<true>(std::forward<F>(func), std::forward<Args>(args)...)))
|
||||
/*!
|
||||
ensures
|
||||
- identical to std::bind_back()
|
||||
- works with C++11 onwards
|
||||
!*/
|
||||
{
|
||||
return detail::make_binder<true>(std::forward<F>(func), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
#endif //DLIB_FUNCTIONAL_Hh_
|
311
dlib/invoke.h
311
dlib/invoke.h
@ -3,315 +3,6 @@
|
||||
#ifndef DLIB_INVOKE_Hh_
|
||||
#define DLIB_INVOKE_Hh_
|
||||
|
||||
#include <functional>
|
||||
#include "type_traits.h"
|
||||
#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
|
||||
!*/
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <class, typename R, typename F, typename... Args>
|
||||
struct is_invocable_r_impl : std::false_type {};
|
||||
|
||||
template <typename R, typename F, typename... Args>
|
||||
struct is_invocable_r_impl<dlib::void_t<std::is_convertible<invoke_result_t<F, Args...>, R>>, R, F, Args...> : std::true_type {};
|
||||
}
|
||||
|
||||
template <typename R, typename F, typename... Args>
|
||||
struct is_invocable_r : detail::is_invocable_r_impl<void, R, F, Args...> {};
|
||||
/*!
|
||||
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>{});
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
}
|
||||
#include "functional.h"
|
||||
|
||||
#endif //DLIB_INVOKE_Hh_
|
||||
|
@ -4,7 +4,7 @@
|
||||
#define DLIB_METApROGRAMMING_Hh_
|
||||
|
||||
#include "constexpr_if.h"
|
||||
#include "invoke.h"
|
||||
#include "functional.h"
|
||||
|
||||
namespace dlib
|
||||
{
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include <string>
|
||||
#include <dlib/constexpr_if.h>
|
||||
#include <dlib/invoke.h>
|
||||
#include <dlib/functional.h>
|
||||
#include <cstdio>
|
||||
#include "tester.h"
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include <array>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <dlib/invoke.h>
|
||||
#include <dlib/functional.h>
|
||||
#include "tester.h"
|
||||
|
||||
namespace
|
||||
@ -332,6 +332,50 @@ namespace
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
constexpr int test_bind_func(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
struct test_bind_func_class
|
||||
{
|
||||
constexpr test_bind_func_class(int v) : val{v} {}
|
||||
int val;
|
||||
constexpr int minus(int arg) const noexcept { return val - arg; }
|
||||
};
|
||||
|
||||
void test_bind_front()
|
||||
{
|
||||
// Pure function
|
||||
static_assert(dlib::bind_front(test_bind_func, 50)(3) == 47, "this should be constexpr");
|
||||
DLIB_TEST(dlib::bind_front(test_bind_func, 50)(3) == 47);
|
||||
|
||||
// Member function
|
||||
static_assert(dlib::bind_front(&test_bind_func_class::minus, test_bind_func_class{50})(3) == 47, "this should be constexpr");
|
||||
DLIB_TEST(dlib::bind_front(&test_bind_func_class::minus, test_bind_func_class{50})(3) == 47);
|
||||
DLIB_TEST(dlib::bind_front(&test_bind_func_class::minus, std::make_shared<test_bind_func_class>(50))(3) == 47);
|
||||
|
||||
// Lambda
|
||||
DLIB_TEST(dlib::bind_front([](int a, int b) {return a - b;}, 50)(3) == 47);
|
||||
}
|
||||
|
||||
void test_bind_back()
|
||||
{
|
||||
// Pure function
|
||||
static_assert(dlib::bind_back(test_bind_func, 50)(3) == -47, "this should be constexpr");
|
||||
DLIB_TEST(dlib::bind_back(test_bind_func, 50)(3) == -47);
|
||||
|
||||
// Member function
|
||||
static_assert(dlib::bind_back(&test_bind_func_class::minus, 50)(test_bind_func_class{3}) == -47, "this should be constexpr");
|
||||
DLIB_TEST(dlib::bind_back(&test_bind_func_class::minus, 50)(test_bind_func_class{3}) == -47);
|
||||
DLIB_TEST(dlib::bind_back(&test_bind_func_class::minus, 50)(std::make_shared<test_bind_func_class>(3)) == -47);
|
||||
|
||||
// Lambda
|
||||
DLIB_TEST(dlib::bind_back([](int a, int b) {return a - b;}, 50)(3) == -47);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
class invoke_tester : public tester
|
||||
{
|
||||
public:
|
||||
@ -350,6 +394,8 @@ namespace
|
||||
test_make_from_tuple();
|
||||
test_invoke_r();
|
||||
test_constexpr();
|
||||
test_bind_front();
|
||||
test_bind_back();
|
||||
}
|
||||
} a;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user