#include #include #include #include "function_traits.cpp" template struct closure; template struct closure, std::tuple<>, std::tuple> : closure, std::tuple, std::tuple> { using Base = closure, std::tuple, std::tuple>; using Base::Base; using Base::operator(); }; template struct closure, std::tuple, std::tuple> : closure, std::tuple, std::tuple> { using Base = closure, std::tuple, std::tuple>; using Base::Base; using Base::operator(); constexpr auto operator()(HeadParams&& arg, Params&&... args) const& { return apply(std::make_index_sequence{}, std::move(arg), std::move(args)...); } constexpr auto operator()(HeadParams&& arg, Params&&... args) && { return std::move(*this).apply(std::make_index_sequence{}, std::move(arg), std::move(args)...); } protected: template constexpr auto apply(std::index_sequence, HeadParams&& arg, Params&&... args) const& { using NewEnv = std::tuple; using NewClosure = closure, std::tuple>; return NewClosure{this->func, std::get(this->env)..., std::move(arg), std::move(args)...}; } template constexpr auto apply(std::index_sequence, HeadParams&& arg, Params&&... args) && { using NewEnv = std::tuple; using NewClosure = closure, std::tuple>; return NewClosure{std::move(this->func), std::get(std::move(this->env))..., std::move(arg), std::move(args)...}; } }; template struct closure, std::tuple, std::tuple<>> { constexpr closure(Func func, Env... args) : func(std::move(func)), env(std::forward(args)...) { } constexpr auto operator()(Params&&... args) const& { return apply(std::make_index_sequence{}, std::move(args)...); } constexpr auto operator()(Params&&... args) && { return std::move(*this).apply(std::make_index_sequence{}, std::move(args)...); } protected: template constexpr auto apply(std::index_sequence, Params&&... args) const& { return func(std::get(env)..., std::move(args)...); } template constexpr auto apply(std::index_sequence, Params&&... args) && { return func(std::get(std::move(env))..., std::move(args)...); } Func func; std::tuple env; }; template auto curry(Func&& func) { using Closure = closure, std::tuple<>, function_arg_tuple_t>; return Closure{ std::move(func) }; }