#include <iostream>
using namespace std;
struct yes {};
template< typename FUNC >
struct is_callable_with
{
template< typename... PARAMS , typename = decltype(std::declval<FUNC>()(std::declval<PARAMS>()...)) >
yes test(int,PARAMS...) const;
void test(...) const;
template< typename... PARAMS >
auto operator() (PARAMS...) const -> decltype(test(0, std::declval<PARAMS>()...));
};
template< typename FUNC, typename CAPTURE >
using is_callable_by_capture = std::is_same< yes, decltype(std::declval<CAPTURE>()(std::declval<is_callable_with<FUNC>>())) >;
// case for when FUNC can be called with the current CAPTURE
template< typename FUNC, typename CAPTURE >
auto curry_impl(FUNC f, CAPTURE c, ...)
{
return c(f);
}
// case for when FUNC cannot be called with current CAPTURE
// and we assume this is because an additional entry in the CAPTURE is needed
template< typename FUNC, typename CAPTURE, typename = std::enable_if_t< !is_callable_by_capture<FUNC,CAPTURE>::value > >
auto curry_impl(FUNC f, CAPTURE c, int)
{
return [f,c](auto new_param) {
auto make_new_capture = [new_param](auto... params) {
return [new_param, params...](auto callee) {
return callee(params..., new_param);
};
};
return curry_impl(f, c(make_new_capture),0);
};
}
template< typename T >
auto curry(T func)
{
return curry_impl(func, [](auto f) {return f();}, 0);
}
//--------------------------
int print(int a, int b, int c)
{
std::cout << "Printing " << a << " " << b << " " << c << std::endl;
return 99;
}
int main() {
auto c_0 = curry(print); // curried function ready to receive arguments
auto c_1 = c_0(1); // first argument provided
auto c_2 = c_1(2); // second argument provided
auto return_value = c_2(3); // final argument
std::cout << "Printing returned " << return_value << std::endl;
return 0;
}
I2luY2x1ZGUgPGlvc3RyZWFtPgp1c2luZyBuYW1lc3BhY2Ugc3RkOwoKc3RydWN0IHllcyB7fTsKCnRlbXBsYXRlPCB0eXBlbmFtZSBGVU5DID4Kc3RydWN0IGlzX2NhbGxhYmxlX3dpdGgKewoJdGVtcGxhdGU8IHR5cGVuYW1lLi4uIFBBUkFNUyAsIHR5cGVuYW1lID0gZGVjbHR5cGUoc3RkOjpkZWNsdmFsPEZVTkM+KCkoc3RkOjpkZWNsdmFsPFBBUkFNUz4oKS4uLikpID4KCXllcyB0ZXN0KGludCxQQVJBTVMuLi4pIGNvbnN0OwoKCXZvaWQgdGVzdCguLi4pIGNvbnN0OwoKCXRlbXBsYXRlPCB0eXBlbmFtZS4uLiBQQVJBTVMgPgoJYXV0byBvcGVyYXRvcigpIChQQVJBTVMuLi4pIGNvbnN0IC0+IGRlY2x0eXBlKHRlc3QoMCwgc3RkOjpkZWNsdmFsPFBBUkFNUz4oKS4uLikpOwp9OwoKdGVtcGxhdGU8IHR5cGVuYW1lIEZVTkMsIHR5cGVuYW1lIENBUFRVUkUgPgp1c2luZyBpc19jYWxsYWJsZV9ieV9jYXB0dXJlID0gc3RkOjppc19zYW1lPCB5ZXMsIGRlY2x0eXBlKHN0ZDo6ZGVjbHZhbDxDQVBUVVJFPigpKHN0ZDo6ZGVjbHZhbDxpc19jYWxsYWJsZV93aXRoPEZVTkM+PigpKSkgPjsKCi8vIGNhc2UgZm9yIHdoZW4gRlVOQyBjYW4gYmUgY2FsbGVkIHdpdGggdGhlIGN1cnJlbnQgQ0FQVFVSRQp0ZW1wbGF0ZTwgdHlwZW5hbWUgRlVOQywgdHlwZW5hbWUgQ0FQVFVSRSA+CmF1dG8gY3VycnlfaW1wbChGVU5DIGYsIENBUFRVUkUgYywgLi4uKQp7CglyZXR1cm4gYyhmKTsKfQoKLy8gY2FzZSBmb3Igd2hlbiBGVU5DIGNhbm5vdCBiZSBjYWxsZWQgd2l0aCBjdXJyZW50IENBUFRVUkUKLy8gYW5kIHdlIGFzc3VtZSB0aGlzIGlzIGJlY2F1c2UgYW4gYWRkaXRpb25hbCBlbnRyeSBpbiB0aGUgQ0FQVFVSRSBpcyBuZWVkZWQKdGVtcGxhdGU8IHR5cGVuYW1lIEZVTkMsIHR5cGVuYW1lIENBUFRVUkUsIHR5cGVuYW1lID0gc3RkOjplbmFibGVfaWZfdDwgIWlzX2NhbGxhYmxlX2J5X2NhcHR1cmU8RlVOQyxDQVBUVVJFPjo6dmFsdWUgPiA+CmF1dG8gY3VycnlfaW1wbChGVU5DIGYsIENBUFRVUkUgYywgaW50KQp7CglyZXR1cm4gW2YsY10oYXV0byBuZXdfcGFyYW0pIHsKCQlhdXRvIG1ha2VfbmV3X2NhcHR1cmUgPSBbbmV3X3BhcmFtXShhdXRvLi4uIHBhcmFtcykgewoJCQlyZXR1cm4gW25ld19wYXJhbSwgcGFyYW1zLi4uXShhdXRvIGNhbGxlZSkgewoJCQkJcmV0dXJuIGNhbGxlZShwYXJhbXMuLi4sIG5ld19wYXJhbSk7CgkJCX07CgkJfTsKCgkJcmV0dXJuIGN1cnJ5X2ltcGwoZiwgYyhtYWtlX25ld19jYXB0dXJlKSwwKTsKCX07Cn0KCnRlbXBsYXRlPCB0eXBlbmFtZSBUID4KYXV0byBjdXJyeShUIGZ1bmMpCnsKCXJldHVybiBjdXJyeV9pbXBsKGZ1bmMsIFtdKGF1dG8gZikge3JldHVybiBmKCk7fSwgMCk7Cn0KCi8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCmludCBwcmludChpbnQgYSwgaW50IGIsIGludCBjKQp7CglzdGQ6OmNvdXQgPDwgIlByaW50aW5nICIgPDwgYSA8PCAiICIgPDwgYiA8PCAiICIgPDwgYyA8PCBzdGQ6OmVuZGw7CglyZXR1cm4gOTk7Cn0KCmludCBtYWluKCkgewoJYXV0byBjXzAgPSBjdXJyeShwcmludCk7IC8vIGN1cnJpZWQgZnVuY3Rpb24gcmVhZHkgdG8gcmVjZWl2ZSBhcmd1bWVudHMKCWF1dG8gY18xID0gY18wKDEpOyAvLyBmaXJzdCBhcmd1bWVudCBwcm92aWRlZAoJYXV0byBjXzIgPSBjXzEoMik7IC8vIHNlY29uZCBhcmd1bWVudCBwcm92aWRlZAoJYXV0byByZXR1cm5fdmFsdWUgPSBjXzIoMyk7IC8vIGZpbmFsIGFyZ3VtZW50CgoJc3RkOjpjb3V0IDw8ICJQcmludGluZyByZXR1cm5lZCAiIDw8IHJldHVybl92YWx1ZSA8PCBzdGQ6OmVuZGw7CgkKCXJldHVybiAwOwp9