#include #include #include #include "function_traits.cpp" // --- template struct apply_args; template struct apply_args, std::tuple> : std::enable_if< std::is_constructible::value, apply_args, std::tuple> >::type { }; template struct apply_args, std::tuple> { using type = std::tuple; }; // --- using empty_tuple_t = std::tuple<>; template struct is_empty_tuple : std::false_type { }; template <> struct is_empty_tuple : std::true_type { }; // ---- template struct currying; template struct currying, std::tuple> { using function_type = FType; using closure_env_type = std::tuple; using param_tuple_type = std::tuple; template constexpr currying(Func&& func, Args&&... args) : func(std::move(func)), env(std::forward(args)...) { } template constexpr auto operator() (Args&&... args) const& { using ArgsTuple = std::tuple; using NewEnv = std::tuple; using NewParams = typename apply_args::type; using NewCurrying = currying; using EnvIndices = std::make_index_sequence; using CanExecute = is_empty_tuple; return apply(EnvIndices{}, std::forward(args)...); } template constexpr auto operator() (Args&&... args) && { using ArgsTuple = std::tuple; using NewEnv = std::tuple; using NewParams = typename apply_args::type; using NewCurrying = currying; using EnvIndices = std::make_index_sequence; using CanExecute = is_empty_tuple; return std::move(*this).template apply(EnvIndices{}, std::forward(args)...); } private: template constexpr auto apply(std::index_sequence, Args&&... args) const& { return apply(CanExecute{}, std::get(env)..., std::forward(args)...); } template constexpr auto apply(std::index_sequence, Args&&... args) && { return std::move(*this).template apply(CanExecute{}, std::get(std::move(env))..., std::forward(args)...); } template constexpr auto apply(std::false_type, Args&&... args) const& { return NewCurrying{ func, std::forward(args)... }; } template constexpr auto apply(std::false_type, Args&&... args) && { return NewCurrying{ std::move(func), std::forward(args)... }; } template constexpr auto apply(std::true_type, Args&&... args) const { return func(std::forward(args)...); } function_type func; closure_env_type env; }; // --- template constexpr auto curry(FType&& func) { using ArgsTuple = function_arg_tuple_t; using CurryType = currying; return CurryType{ std::move(func) }; }