1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
|
#include <tuple>
#include <type_traits>
#include <cassert>
namespace detail {
template < typename Fn, typename Args, std::size_t... Is >
constexpr auto
partially_apply_impl(Fn fn, Args args,
std::index_sequence< Is... >)
{
return [fn{std::move(fn)}, args] (auto... rest)
{
return fn(std::get<Is>(args)..., rest...);
};
}
}
template < typename Fn, typename Args >
constexpr auto partially_apply(Fn fn, Args args) {
return detail::partially_apply_impl(
fn, args,
std::make_index_sequence< std::tuple_size<
std::remove_reference_t< std::remove_cv_t< Args > > >::value >());
}
template < int N >
struct curry_t
{
template < typename Fn >
constexpr auto
operator()(Fn fn) const {
return [fn](auto... args) {
constexpr int remaining_free_variables =
N - static_cast< int >(sizeof...(args));
if constexpr (remaining_free_variables > 0)
return curry_t< remaining_free_variables >{}(
partially_apply(fn, std::make_tuple(args...)));
else
return fn(args...);
};
}
};
template < int N > inline constexpr curry_t< N > curry{};
struct equal_fn
{
template <typename First, typename Last>
constexpr auto operator()(First first, Last last) const
{
return first == last;
}
};
inline constexpr auto equal = curry<2>(equal_fn{});
int main()
{
assert(equal(1)(1));
assert(equal(1)()(1));
assert(equal(1, 1));
assert(equal()(1, 1));
assert(! equal(1)(2));
assert(! equal(1)()(2));
assert(! equal(1, 2));
assert(! equal()(1, 2));
}
| |