基于 C++11 的可调用对象柯里化库
#include "currying.hpp"
double func(int i, double d) {
return i + d;
}
对 func
柯里化:
cedar::currying<double(int, double)> c(func);
或
auto c = cedar::make_currying(func);
两种方式.
auto c1 = c(2);
auto c2 = c1(3.3);
亦可
auto c2 = c(2)(3.3);
2020.09.17 新添了一种传参方式!
auto c2 = c(2, 3.3); // 可以传递 [1, args_size] 个参数
这时候, c2
依旧是一个柯里化对象, 还没有进行实际调用.
std::cout << c2() << std::endl;
或
std::cout << c2 << std::endl;
得
5.3
第一种方式的理解, 是因为 c2
依旧是个可调用对象, 只不过参数列表为空.
而第二种方式的存在, 是因为 参数列表为空的柯里化对象 具有一个到返回值的隐式转换.
设计第二种方式的原因很简单:
std::cout << c(2)(3.3) << std::endl;
我不希望如上代码会因为没有第二种方式的原因写成这样:
std::cout << c(2)(3.3)() << std::endl;
需要注意的是, 在没有对 c2
进行调用操作, 也就是说没有调用 operator()
或 operator R
时, 不会做 对 被柯里化的可调用对象 的调用操作!
这一切都是惰性的!
double f(int &i, double d) {
return i + d;
}
_currying_impl<double(int &, double), std::tuple<int &>, double>
create() {
int i = 2;
return make_currying(f)(i);
}
使用如上 create()
构建的柯里化对象将导致未定义行为, 因为存在悬垂引用!
若 f
的函数签名改为
double f(const int &i, double d);
依旧会形成悬垂引用, 导致未定义行为.
- 我希望我在将来能有能力优化形参为
const &
的情况下的柯里化行为, 使用户可定义柯里化类内部是否存储一份副本, 以避免悬垂引用的产生. - 我注意到柯里化类的类型非常复杂, 导致在没有
C++14
支持的情况下 (C++14
的返回值可写auto
) 想返回一个柯里化对象有着巨大的不便, 我将提供一个using
简化这一工作.