Last active
August 29, 2015 14:12
-
-
Save Garciat/c7e4bef299ee5c607948 to your computer and use it in GitHub Desktop.
Function currying in C++14 (function_traits.cpp: https://gist.github.com/Garciat/cafe27d04cfdff0e891e)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <type_traits> | |
#include <utility> | |
#include <tuple> | |
#include "function_traits.cpp" | |
// --- | |
template <typename Args, typename Params> | |
struct apply_args; | |
template <typename HeadArgs, typename... Args, typename HeadParams, typename... Params> | |
struct apply_args<std::tuple<HeadArgs, Args...>, std::tuple<HeadParams, Params...>> | |
: std::enable_if< | |
std::is_constructible<HeadParams, HeadArgs>::value, | |
apply_args<std::tuple<Args...>, std::tuple<Params...>> | |
>::type | |
{ }; | |
template <typename... Params> | |
struct apply_args<std::tuple<>, std::tuple<Params...>> { | |
using type = std::tuple<Params...>; | |
}; | |
// --- | |
using empty_tuple_t = std::tuple<>; | |
template <typename TupleType> | |
struct is_empty_tuple : std::false_type { }; | |
template <> | |
struct is_empty_tuple<empty_tuple_t> : std::true_type { }; | |
// ---- | |
template <typename FType, typename Env, typename Params> | |
struct currying; | |
template <typename FType, typename... Env, typename... Params> | |
struct currying<FType, std::tuple<Env...>, std::tuple<Params...>> { | |
using function_type = FType; | |
using closure_env_type = std::tuple<Env...>; | |
using param_tuple_type = std::tuple<Params...>; | |
template <typename Func, typename... Args> | |
constexpr | |
currying(Func&& func, Args&&... args) : | |
func(std::move(func)), | |
env(std::forward<Args>(args)...) | |
{ } | |
template <typename... Args> | |
constexpr | |
auto operator() (Args&&... args) const& { | |
using ArgsTuple = std::tuple<Args...>; | |
using NewEnv = std::tuple<Env..., Args...>; | |
using NewParams = typename apply_args<ArgsTuple, param_tuple_type>::type; | |
using NewCurrying = currying<FType, NewEnv, NewParams>; | |
using EnvIndices = std::make_index_sequence<sizeof...(Env)>; | |
using CanExecute = is_empty_tuple<NewParams>; | |
return apply<NewCurrying, CanExecute>(EnvIndices{}, std::forward<Args>(args)...); | |
} | |
template <typename... Args> | |
constexpr | |
auto operator() (Args&&... args) && { | |
using ArgsTuple = std::tuple<Args...>; | |
using NewEnv = std::tuple<Env..., Args...>; | |
using NewParams = typename apply_args<ArgsTuple, param_tuple_type>::type; | |
using NewCurrying = currying<FType, NewEnv, NewParams>; | |
using EnvIndices = std::make_index_sequence<sizeof...(Env)>; | |
using CanExecute = is_empty_tuple<NewParams>; | |
return std::move(*this).template apply<NewCurrying, CanExecute>(EnvIndices{}, std::forward<Args>(args)...); | |
} | |
private: | |
template <typename NewCurrying, typename CanExecute, typename... Args, size_t... Indices> | |
constexpr | |
auto apply(std::index_sequence<Indices...>, Args&&... args) const& { | |
return apply<NewCurrying>(CanExecute{}, std::get<Indices>(env)..., std::forward<Args>(args)...); | |
} | |
template <typename NewCurrying, typename CanExecute, typename... Args, size_t... Indices> | |
constexpr | |
auto apply(std::index_sequence<Indices...>, Args&&... args) && { | |
return std::move(*this).template apply<NewCurrying>(CanExecute{}, std::get<Indices>(std::move(env))..., std::forward<Args>(args)...); | |
} | |
template <typename NewCurrying, typename... Args> | |
constexpr | |
auto apply(std::false_type, Args&&... args) const& { | |
return NewCurrying{ func, std::forward<Args>(args)... }; | |
} | |
template <typename NewCurrying, typename... Args> | |
constexpr | |
auto apply(std::false_type, Args&&... args) && { | |
return NewCurrying{ std::move(func), std::forward<Args>(args)... }; | |
} | |
template <typename NewCurrying, typename... Args> | |
constexpr | |
auto apply(std::true_type, Args&&... args) const { | |
return func(std::forward<Args>(args)...); | |
} | |
function_type func; | |
closure_env_type env; | |
}; | |
// --- | |
template <typename FType> | |
constexpr | |
auto curry(FType&& func) { | |
using ArgsTuple = function_arg_tuple_t<FType>; | |
using CurryType = currying<FType, empty_tuple_t, ArgsTuple>; | |
return CurryType{ std::move(func) }; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "curry.cpp" | |
#include "meow.cpp" | |
#include <iostream> | |
int main() { | |
{ | |
auto add = curry([](meow, int a, int b, int c) { return a + b + c; }); | |
std::cout << add(meow{})(5)(5)(5) << std::endl; | |
} | |
meow::report(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment