C ++中的Lambda-Over-Lambda 14
如何recursionlambda调用结束/终止?
#include <cstdio> auto terminal = [](auto term) // <---------+ { // | return [=] (auto func) // | ??? { // | return terminal(func(term)); // >---------+ }; }; auto main() -> int { auto hello =[](auto s){ fprintf(s,"Hello\n"); return s; }; auto world =[](auto s){ fprintf(s,"World\n"); return s; }; terminal(stdout) (hello) (world) ; return 0; }
我在这里错过了什么?
Running code
这不是recursion函数调用,请逐步查看:
-
terminal(stdout)
– 这只是返回一个已捕获stdout
的lambda - 使用lambda
hello
(执行lambda(func(term)
)来调用1.的结果,其结果被传递给terminal()
,它简单地返回1中的lambda。 - 2的结果是用lambda
world
调用的,它与2相同,这次返回值被丢弃…
调用本身不是recursion的。 它返回一个函数对象,如果调用该对象,将再次调用terminal
来生成另一个函数对象。
所以terminal(stdout)
返回一个函数捕获stdout
,可以调用另一个函数对象。 再次调用(hello)
,用捕获的术语stdout
调用hello
函子,输出"Hello"
; 调用terminal
并返回另一个functor,这次捕获hello
的返回值 – 这仍然是stdout
。 调用那个函数, (world)
,再次一样,输出"World"
。
这里的关键是明白这是有效的:
world(hello(stdout));
并将打印“Hello World”。 lambdasrecursion系列可以展开为
#include <cstdio> auto terminal = [](auto term) // <---------+ { // | return [=] (auto func) // | ??? { // | return terminal(func(term)); // >---------+ }; }; /* terminal(stdout) -returns> anonymous_lambda which captures stdout (functor) anonymous_lambda(hello) is called, func(term) is hello(stdout) and prints "Hello" and returns stdout, the anonymous_lambda -returns> terminal(stdout) (the above 2 lines start again) terminal(stdout) is called and -returns> anonymous_lambda which captures stdout (functor) anonymous_lambda(world) is called, func(term) is world(stdout) and prints "World" and returns stdout, the anonymous_lambda -returns> terminal(stdout) terminal(stdout) is called and -returns> anonymous_lambda which captures stdout (functor) nobody uses that anonymous_lambda.. end. */ auto main() -> int { auto hello =[](auto s){ fprintf(s,"Hello\n"); return s; }; auto world =[](auto s){ fprintf(s,"World\n"); return s; }; world(hello(stdout)); terminal(stdout) (hello) (world) ; return 0; }
Coliru的例子
它可以在内部翻译成以下内容:
#include <cstdio> template <typename T> struct unnamed_lambda { unnamed_lambda(T term) : captured_term(term) {} template <typename A> unnamed_lambda operator()(A func); T captured_term; }; struct terminal_lambda { template <typename A> unnamed_lambda<A> operator()(A term) { return unnamed_lambda<A>{term}; } }; terminal_lambda terminal; template <typename T> template <typename A> unnamed_lambda<T> unnamed_lambda<T>::operator()(A func) { return terminal(func(captured_term)); } struct Hello { FILE* operator()(FILE* s) { fprintf(s, "Hello\n"); return s; } }; struct World { FILE* operator()(FILE* s) { fprintf(s, "World\n"); return s; } }; int main() { Hello hello; World world; unnamed_lambda<FILE*> l1 = terminal(stdout); unnamed_lambda<FILE*> l2 = l1(hello); unnamed_lambda<FILE*> l3 = l2(world); // same as: terminal(stdout)(hello)(world); }
现场演示
实际上,这是编译器在 lambdas 后面做的 (有一些近似)。
我认为混淆的根源来自于读取lambda声明作为lambda调用。 确实在这里:
auto terminal = [](auto term) // <---------+ { // | return [=] (auto func) // | ??? { // | return terminal(func(term)); // >---------+ }; };
作者只是宣布了一个lambda terminal
,它只需要一个任意的参数,并返回一个无名的lambda,仅此而已! 我们来看看这个无名的lambda,它:
- 接受一个可调用的对象
func
作为参数,并在copy-captured参数term
上调用它 - 返callback用
func(term)
结果的terminal调用结果; 所以它返回另一个未命名的lambda捕获func(term)
的结果,但是这个lambda现在没有被调用,没有recursion。
现在主要的诀窍应该更加清楚:
-
terminal(stdout)
返回一个未命名的lambda已捕获标准输出。 -
(hello)
将这个未命名的lambda作为parameter passing给你可调用的hello。 这在之前捕获的stdout上被调用。hello(stdout)
再次返回stdout,用作调用terminal的参数,返回另一个已经捕获stdout的未命名的lambda。 -
(world)
相同2。
-
terminal(stdout)返回一个函数,让我们称之为函数
x
,用paramfunc
。 所以:terminal(stdout) ==> x(func) { return terminal(func(stdout)) };
-
现在terminal(标准输出)(你好)调用函数
x(hello)
:terminal(stdout)(hello) ==> x(hello) { return terminal(hello(stdout)) };
这会导致
hello
函数被调用并再次返回函数x
。 -
现在terminal(标准)(你好)(世界)调用函数
x(world)
:terminal(stdout)(hello) ==> x(world) { return terminal(world(stdout)) };
这导致
world
函数被调用,并返回函数x
。 函数x
现在不再被调用,因为没有更多的参数。