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:
pfeatherstone 2023-01-04 12:38:36 +00:00 committed by GitHub
parent 1ce7b9cbc5
commit b9ac468169
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 449 additions and 314 deletions

View File

@ -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
View 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_

View File

@ -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_

View File

@ -4,7 +4,7 @@
#define DLIB_METApROGRAMMING_Hh_
#include "constexpr_if.h"
#include "invoke.h"
#include "functional.h"
namespace dlib
{

View File

@ -3,7 +3,7 @@
#include <string>
#include <dlib/constexpr_if.h>
#include <dlib/invoke.h>
#include <dlib/functional.h>
#include <cstdio>
#include "tester.h"

View File

@ -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;
}