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函数调用,请逐步查看:

  1. terminal(stdout) – 这只是返回一个已捕获stdout的lambda
  2. 使用lambda hello (执行lambda( func(term) )来调用1.的结果,其结果被传递给terminal() ,它简单地返回1中的lambda。
  3. 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。

现在主要的诀窍应该更加清楚:

  1. terminal(stdout)返回一个未命名的lambda已捕获标准输出。
  2. (hello)将这个未命名的lambda作为parameter passing给你可调用的hello。 这在之前捕获的stdout上被调用。 hello(stdout)再次返回stdout,用作调用terminal的参数,返回另一个已经捕获stdout的未命名的lambda。
  3. (world)相同2。
  1. terminal(stdout)返回一个函数,让我们称之为函数x ,用param func 。 所以:

    terminal(stdout) ==> x(func) { return terminal(func(stdout)) };

  2. 现在terminal(标准输出)(你好)调用函数x(hello)

    terminal(stdout)(hello) ==> x(hello) { return terminal(hello(stdout)) };

    这会导致hello函数被调用并再次返回函数x

  3. 现在terminal(标准)(你好)(世界)调用函数x(world)

    terminal(stdout)(hello) ==> x(world) { return terminal(world(stdout)) };

    这导致world函数被调用,并返回函数x 。 函数x现在不再被调用,因为没有更多的参数。