template<typename Function,typename... Arguments> auto curry(Function func,Arguments... args) { return [=](auto... rest) { return func(args...,rest...); }; } int main() { auto add = [](auto x,auto y) { return x + y; }; auto add4 = curry(add,4); std::cout << add4(3) << '\n'; //output: 7. (Ok) }
解决方法
基本上,它意味着使用一定数量的参数来减少函数,以创建另一个函数,其中一些参数的值是固定的.
我的例子,原始函数是add(x,y),它有两个参数x和y.通过将x设置为4来减少函数的arity add,并创建缩减函数add4(y),例如
add4(y)= add(x,y)其中x = 4
现在如何在您的c代码中实现这一目标?借助可变参数模板,可变参数函数和lambda函数.
Lambda functions是从C11开始的c.本质上它们是动态创建的匿名函数,可以存储在变量中.您在main()中创建add作为lambda:
auto add = [](auto x,auto y) { return x + y; };
一个人通过模式[](参数列表){function-body}识别lambda;
注意:[]并不总是空的,请参阅“捕获变量”there,我们稍后会再回过头来看.
现在curry函数的目的是将这些lambdas函数func和一定数量的值中的一个作为参数,并通过将值按顺序分配给func的第一个参数来定义新函数.
variadic template参数Arguments … args允许使用“一定数量的参数”机制,它允许使用任意数量的类型作为模板参数调用模板(只要它们被称为编译时).所以在我们的例子中,传递的参数是4,因此Arguments … args将被int替换,而curry的实例将接受lambda和int作为参数.
如果我们看一下curry的代码,我们看到它本身只是一个lambda函数(它是一个variadic function,就像printf()),它的唯一目的是连接在实例化模板时其值已经修复的参数( args …)以及那些值作为参数传递给curried函数的人(rest …).
[=]符号是lambda函数的特殊捕获,它允许使用函数体中的所有局部变量(这里允许使用args).
所以要把它包起来,这是你的main函数中发生的事情:
>您创建一个名为add的变量,其中包含一个lambda
函数,取两个参数并添加它们.
>当您调用咖喱(添加,4)时,您实例化咖喱模板.
>第一个模板参数Function是add的类型(一个lambda采用两个int并返回一个int)
>第二个可变参数只包含一种类型:类型4,即int
实例化的咖喱函数看起来像这样
curry( (int,int)->(int) func,int arg){ return [=](auto... rest) {return func(arg,rest...);}; }
请注意,由于自动和模板类型扣除,您永远不会看到这些类型.
>然后使用func = add和arg = 4调用此实例
>您将此实例化的结果存储在add4中,现在这是一个带有一个参数的lambda.然后你可以调用add4 with 3作为参数(rest …是3),然后调用add(4,3)并返回7.
请注意,从技术上讲,您可以尝试使用多个参数调用add4,因为curried函数是一个可变参数函数.只有当它在调用add时它没有这些额外参数的位置时,编译器才会失败(参见here)