C++11:lambda、柯里化
C++11: lambda, currying
我有以下代码。你能给我解释一下它是如何工作的吗?
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)
}
首先,您必须知道什么 currying is, or in your question, this is specifically a case of partial application(与柯里化相关,但略有不同)。
基本上,这意味着减少一个具有一定数量参数的函数来创建另一个具有一些参数值固定的函数。
我以你为例,原始函数是add(x,y)
,它有两个参数x和y。您通过将 x 设置为 4 reduce 函数的 arity add 并创建缩减函数 add4(y)
例如
add4(y) = add(x,y) 其中 x = 4
现在,这是如何在您的 C++ 代码中实现的?在可变参数模板、可变参数函数和lambda函数.
的帮助下
Lambda functions 从 C++11 开始在 C++ 中。本质上它们是动态创建的匿名函数,可以存储在变量中。您将 add
创建为 main()
中的 lambda :
auto add = [](auto x, auto y) {
return x + y;
};
通过模式 [] (list-of-arguments) {function-body};
识别 lambda
注意:[]
并不总是空的,请参阅 "capturing variables" there,我们稍后再讲。
现在 curry 函数的目的是将其中一个 lambdas 函数 func
和一定数量的值作为参数,并通过 [= 定义一个 新函数 102=]按顺序将值分配给func
的第一个参数。
一定数量的参数”机制被variadic template参数Arguments... args
允许,它允许使用任意数量的类型调用模板模板参数(只要它们被称为编译时)。所以在我们的例子中,传递的参数是 4,所以 Arguments... args
将被 int
替换,并且 curry
的实例将接受一个 lambda 和一个 int
作为参数。
如果我们查看 curry
的代码,我们会发现它本身只是一个 lambda 函数(它是一个 variadic function,就像 printf()
一样)其唯一目的是将在实例化模板时已经固定值的参数(args...
)和那些值作为参数传递给柯里化函数的参数(rest...
).
连接起来
[=]符号是lambda函数的特殊捕获,允许在函数体中使用所有局部变量(这里允许使用args
) .
总结一下,这是您的主要功能中发生的事情:
- 您创建了一个名为
add
的变量,其中包含一个 lambda
函数,接受两个参数并将它们相加。
- 当您调用
curry(add,4)
时,您实例化了 curry
模板。
- 第一个模板参数
Function
是 add
的类型(一个 lambda 接受两个 int
和 returning 一个 int
)
- 第二个可变参数只包含一种类型:
4
的类型,即int
实例化的 curry
函数如下所示
curry( (int,int)->(int) func, int arg){
return [=](auto... rest) {return func(arg, rest...);};
}
请注意,由于 auto
和模板类型推导,您永远不会看到这些类型。
然后您使用 func
= add
和 arg
= 4
调用此实例
您将此实例化的结果存储在 add4
中,它现在是一个带一个参数的 lambda。然后你可以用 3 作为参数调用 add4
(rest...
是 3),然后调用 add(4,3)
和 return 7.
请注意,从技术上讲,您可以尝试使用多个参数调用 add4
,因为柯里化函数是一个可变参数函数。编译器只有在调用 add
时发现没有地方存放这些额外参数时才会失败(参见 here)
我有以下代码。你能给我解释一下它是如何工作的吗?
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)
}
首先,您必须知道什么 currying is, or in your question, this is specifically a case of partial application(与柯里化相关,但略有不同)。
基本上,这意味着减少一个具有一定数量参数的函数来创建另一个具有一些参数值固定的函数。
我以你为例,原始函数是add(x,y)
,它有两个参数x和y。您通过将 x 设置为 4 reduce 函数的 arity add 并创建缩减函数 add4(y)
例如
add4(y) = add(x,y) 其中 x = 4
现在,这是如何在您的 C++ 代码中实现的?在可变参数模板、可变参数函数和lambda函数.
的帮助下Lambda functions 从 C++11 开始在 C++ 中。本质上它们是动态创建的匿名函数,可以存储在变量中。您将 add
创建为 main()
中的 lambda :
auto add = [](auto x, auto y) {
return x + y;
};
通过模式 [] (list-of-arguments) {function-body};
注意:[]
并不总是空的,请参阅 "capturing variables" there,我们稍后再讲。
现在 curry 函数的目的是将其中一个 lambdas 函数 func
和一定数量的值作为参数,并通过 [= 定义一个 新函数 102=]按顺序将值分配给func
的第一个参数。
一定数量的参数”机制被variadic template参数Arguments... args
允许,它允许使用任意数量的类型调用模板模板参数(只要它们被称为编译时)。所以在我们的例子中,传递的参数是 4,所以 Arguments... args
将被 int
替换,并且 curry
的实例将接受一个 lambda 和一个 int
作为参数。
如果我们查看 curry
的代码,我们会发现它本身只是一个 lambda 函数(它是一个 variadic function,就像 printf()
一样)其唯一目的是将在实例化模板时已经固定值的参数(args...
)和那些值作为参数传递给柯里化函数的参数(rest...
).
[=]符号是lambda函数的特殊捕获,允许在函数体中使用所有局部变量(这里允许使用args
) .
总结一下,这是您的主要功能中发生的事情:
- 您创建了一个名为
add
的变量,其中包含一个 lambda 函数,接受两个参数并将它们相加。 - 当您调用
curry(add,4)
时,您实例化了curry
模板。- 第一个模板参数
Function
是add
的类型(一个 lambda 接受两个int
和 returning 一个int
) - 第二个可变参数只包含一种类型:
4
的类型,即int
- 第一个模板参数
实例化的 curry
函数如下所示
curry( (int,int)->(int) func, int arg){
return [=](auto... rest) {return func(arg, rest...);};
}
请注意,由于 auto
和模板类型推导,您永远不会看到这些类型。
然后您使用
func
=add
和arg
= 4 调用此实例
您将此实例化的结果存储在
add4
中,它现在是一个带一个参数的 lambda。然后你可以用 3 作为参数调用add4
(rest...
是 3),然后调用add(4,3)
和 return 7.
请注意,从技术上讲,您可以尝试使用多个参数调用 add4
,因为柯里化函数是一个可变参数函数。编译器只有在调用 add
时发现没有地方存放这些额外参数时才会失败(参见 here)