Created
November 13, 2019 11:25
-
-
Save Y-Less/decb4cd503b3eb5de1f9992ce82d7b66 to your computer and use it in GitHub Desktop.
Curry functions. Can be improved with better move semantics.
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 <tuple> | |
#include <functional> | |
template <typename RET, typename FUNC, int N, typename... ARGS> | |
struct CurriedCaller | |
{ | |
template <typename... TUPLED> | |
static RET Call(FUNC & f, std::tuple<TUPLED...> const & t, ARGS ...args) | |
{ | |
return CurriedCaller<RET, FUNC, N - 1, decltype (std::get<N - 1>(t)), ARGS...>::Call(f, t, std::get<N - 1>(t), args...); | |
} | |
}; | |
template <typename RET, typename FUNC, typename... ARGS> | |
struct CurriedCaller<RET, FUNC, 0, ARGS...> | |
{ | |
template <typename... TUPLED> | |
static RET Call(FUNC & f, std::tuple<TUPLED...> const &, ARGS ...args) | |
{ | |
return f(args...); | |
} | |
}; | |
template <typename RET, typename FUNC, typename TUPLE, typename... ARGS> | |
class CurriedContainer | |
{ | |
public: | |
CurriedContainer(FUNC & func, TUPLE && saved) | |
: | |
func_(func), | |
saved_(std::move(saved)) | |
{ | |
} | |
RET operator()() | |
{ | |
return CurriedCaller<std::tuple_size<TUPLE>()>::Call(func_, saved_); | |
} | |
private: | |
TUPLE | |
saved_; | |
FUNC | |
func_; | |
}; | |
template <typename RET, typename FUNC, typename TUPLE, typename A, typename... ARGS> | |
class CurriedContainer<RET, FUNC, TUPLE, A, ARGS...> | |
{ | |
public: | |
CurriedContainer(FUNC func, TUPLE && saved) | |
: | |
func_(std::move(func)), | |
saved_(std::move(saved)) | |
{ | |
} | |
RET operator()(A one) | |
{ | |
return CurriedCaller<RET, FUNC, std::tuple_size<TUPLE>::value, A>::Call(func_, saved_, one); | |
} | |
private: | |
TUPLE | |
saved_; | |
FUNC | |
func_; | |
}; | |
template <typename RET, typename FUNC, typename TUPLE, typename A, typename B, typename... ARGS> | |
class CurriedContainer<RET, FUNC, TUPLE, A, B, ARGS...> | |
{ | |
public: | |
CurriedContainer(FUNC func, TUPLE && saved) | |
: | |
func_(std::move(func)), | |
saved_(std::move(saved)) | |
{ | |
} | |
auto operator()(A param) | |
{ | |
return CurriedContainer<RET, FUNC, decltype (std::tuple_cat(saved_, std::make_tuple(param))), B, ARGS...>(func_, std::tuple_cat(saved_, std::make_tuple(param))); | |
} | |
RET operator()(A one, B two, ARGS... rest) | |
{ | |
return CurriedCaller<RET, FUNC, std::tuple_size<TUPLE>::value, A, B, ARGS...>::Call(func_, saved_, one, two, rest...); | |
} | |
private: | |
TUPLE | |
saved_; | |
FUNC | |
func_; | |
}; | |
template <typename RET, typename... ARGS> | |
auto Curry(std::function<RET(ARGS...)> & func) | |
{ | |
return CurriedContainer<RET, std::function<RET(ARGS...)>, std::tuple<>, ARGS...>(func, std::make_tuple()); | |
} | |
template <typename RET, typename... ARGS> | |
auto Curry(RET (*func)(ARGS...)) | |
{ | |
return CurriedContainer<RET, std::function<RET(ARGS...)>, std::tuple<>, ARGS...>(std::function<RET(ARGS...)>(func), std::make_tuple()); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment