What is currying?
How can currying be done in C++?
Please Explain binders in STL container?
I implemented currying with variadic templates as well (see Julian's answer). However, I did not make use of recursion or std::function
. Note: It uses a number of C++14 features.
The provided example (main
function) actually runs at compile time, proving that the currying method does not trump essential optimizations by the compiler.
The code can be found here: https://gist.github.com/Garciat/c7e4bef299ee5c607948
with this helper file: https://gist.github.com/Garciat/cafe27d04cfdff0e891e
The code still needs (a lot of) work, which I may or may not complete soon. Either way, I'm posting this here for future reference.
Posting code in case links die (though they shouldn't):
#include
#include
#include
#include
// ---
template
struct function_traits;
template
struct function_traits {
using arity = std::integral_constant;
using result_type = RType;
template
using arg_type = typename std::tuple_element>::type;
};
// ---
namespace details {
template
struct function_type_impl
: function_type_impl
{ };
template
struct function_type_impl {
using type = RType(ArgTypes...);
};
template
struct function_type_impl {
using type = RType(ArgTypes...);
};
template
struct function_type_impl> {
using type = RType(ArgTypes...);
};
template
struct function_type_impl {
using type = RType(ArgTypes...);
};
template
struct function_type_impl {
using type = RType(ArgTypes...);
};
}
template
struct function_type
: details::function_type_impl::type>::type>
{ };
// ---
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;
};
// ---
template
struct is_empty_tuple : std::false_type { };
template <>
struct is_empty_tuple> : std::true_type { };
// ----
template
struct currying;
template
struct currying, std::tuple> {
std::tuple given_args;
FType func;
template
constexpr
currying(Func&& func, GivenArgsReal&&... args) :
given_args(std::forward(args)...),
func(std::move(func))
{ }
template
constexpr
auto operator() (Args&&... args) const& {
using ParamsTuple = std::tuple;
using ArgsTuple = std::tuple;
using RestArgsPrime = typename apply_args::type;
using CanExecute = is_empty_tuple;
return apply(CanExecute{}, std::make_index_sequence{}, std::forward(args)...);
}
template
constexpr
auto operator() (Args&&... args) && {
using ParamsTuple = std::tuple;
using ArgsTuple = std::tuple;
using RestArgsPrime = typename apply_args::type;
using CanExecute = is_empty_tuple;
return std::move(*this).apply(CanExecute{}, std::make_index_sequence{}, std::forward(args)...);
}
private:
template
constexpr
auto apply(std::false_type, std::index_sequence, Args&&... args) const& {
using ParamsTuple = std::tuple;
using ArgsTuple = std::tuple;
using RestArgsPrime = typename apply_args::type;
using CurryType = currying, RestArgsPrime>;
return CurryType{ func, std::get(given_args)..., std::forward(args)... };
}
template
constexpr
auto apply(std::false_type, std::index_sequence, Args&&... args) && {
using ParamsTuple = std::tuple;
using ArgsTuple = std::tuple;
using RestArgsPrime = typename apply_args::type;
using CurryType = currying, RestArgsPrime>;
return CurryType{ std::move(func), std::get(std::move(given_args))..., std::forward(args)... };
}
template
constexpr
auto apply(std::true_type, std::index_sequence, Args&&... args) const& {
return func(std::get(given_args)..., std::forward(args)...);
}
template
constexpr
auto apply(std::true_type, std::index_sequence, Args&&... args) && {
return func(std::get(std::move(given_args))..., std::forward(args)...);
}
};
// ---
template
constexpr
auto curry(FType&& func, std::index_sequence) {
using RealFType = typename function_type::type;
using FTypeTraits = function_traits;
using CurryType = currying, std::tuple...>>;
return CurryType{ std::move(func) };
}
template
constexpr
auto curry(FType&& func) {
using RealFType = typename function_type::type;
using FTypeArity = typename function_traits::arity;
return curry(std::move(func), std::make_index_sequence{});
}
// ---
int main() {
auto add = curry([](int a, int b) { return a + b; });
std::cout << add(5)(10) << std::endl;
}