intadd(int a, int b){ return a + b; } autoinc(int x){ return Reimuda::curry<2>(add)(x); } intmain(){ auto f1 = inc(1); auto f2 = inc(2); auto f3 = inc(3); auto f4 = inc(4); auto f5 = inc(5); std::cout << f1(1) << std::endl; }
template<typename F> structfunction_traits : public __detail::__function_traits<std::decay_t<F>> {};
}
curry的实现
采用第一种思路实现。
首先定义一个可以缓存参数的cacher作为curry的返回值。模板中的TA表示”Tuple of Args”,即保存的参数元组的类型,A和As表示之后还剩下的参数类型。cacher接收一个参数,用其扩展cached_args,将扩展后的cached_args传给一个新的cacher,并返回新cacher。
template<std::size_t I, typename T, typename = void> struct __tuple_drop_n; template<std::size_t I, typename T> using__tuple_drop_n_t = typename __tuple_drop_n<I, T>::type; template<typename ...Ts> struct__tuple_drop_n<0, std::tuple<Ts...>> { using type = std::tuple<Ts...>; }; template<std::size_t I, typename T, typename ...Ts> struct__tuple_drop_n<I, std::tuple<T, Ts...>, std::enable_if_t<(I > 0)>> { using type = __tuple_drop_n_t<I - 1, std::tuple<Ts...>>; };
简单测试
curry的测试
call-by-value
1 2 3 4 5 6 7
auto add = [](int a, int b, int c, int d) { return a + b + c + d; }; auto c_add = curry(add); std::cout << c_add(1)(2)(3)(4) << std::endl; // 10 auto c_add_1 = c_add(1); std::cout << c_add_1(2)(3)(4) << std::endl; // 10
call-by-reference
1 2 3 4 5 6 7 8 9 10 11 12 13
auto genso_concat = [](std::string &s) { returncurry([&](std::string &a, const std::string &b) { auto tmp = a; a += " " + b + " " + s; s += " " + b + " " + tmp; }); }; auto s1 = std::string("Reimu"), s2 = std::string("Marisa"); auto f = genso_concat(s1); auto ff = f(s2); ff("love"); std::cout << s1 << std::endl; // Reimu love Marisa std::cout << s2 << std::endl; // Marisa love Reimu
closure?
1 2 3 4 5 6 7 8 9 10 11
auto greater_than = [](int x) { returncurry([](int a, int b) { return a < b; })(x); }; auto gt_0 = greater_than(0); auto gt_1 = greater_than(1); auto gt_2 = greater_than(2); auto gt_3 = greater_than(3); std::cout << std::boolalpha; std::cout << gt_0(-1) << std::endl; // false std::cout << gt_0(0) << std::endl; // false std::cout << gt_0(1) << std::endl; // true
auto pair_assign = [](int &a, int &b, int aa, int bb) -> void { a = aa, b = bb; }; int a = 0, b = 0; auto assign_a_b = partial(pair_assign, a, b); assign_a_b(1, 2); std::cout << a << ", " << b << std::endl; // 1, 2
non-copyable-function
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
std::unique_ptr<int> uip{newint{0}}; auto uf = [p = std::move(uip)](int a, int b) { return *p += a + b; }; { auto f = partial(std::ref(uf), 1); std::cout << f(1) << std::endl; // 2 std::cout << f(1) << std::endl; // 4 std::cout << f(1) << std::endl; // 6 } { auto f = partial(std::move(uf), 1); std::cout << f(1) << std::endl; // 8 std::cout << f(1) << std::endl; // 10 std::cout << f(1) << std::endl; // 12 }