[英]Lambda-Over-Lambda in C++14
接下来的递归lambda调用如何结束/终止?
#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;
}
我在这里想念什么?
这不是递归函数调用,请分步看一下:
terminal(stdout)
-这只是返回捕获了stdout
的lambda hello
调用1.的结果,它执行lambda( func(term)
),其结果被传递给terminal()
,后者仅像1一样返回lambda。 world
调用,它的功能与2相同,但是这次返回值被丢弃了。 调用本身不是递归的。 它返回一个功能对象,如果调用该功能对象,它将再次调用terminal
以生成另一个功能对象。
因此, terminal(stdout)
返回一个函子,该函子捕获stdout
并可以与另一个函数对象一起调用。 再次调用(hello)
,使用捕获的术语stdout
调用hello
函子,输出"Hello"
; 调用terminal
并返回另一个函数,这次捕获了hello
的返回值-仍然是stdout
。 再次调用该函子(world)
,输出"World"
。
这里的关键是要了解这是有效的:
world(hello(stdout));
并打印“ Hello World”。 递归的lambda系列可以展开为
#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;
}
可以在内部将其转换为如下所示的内容:
#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);
}
实际上,这就是编译器使用lambda(有一些近似值) 在后台执行的操作 。
我认为混淆的根源来自将lambda声明读取为lambda调用。 确实在这里:
auto terminal = [](auto term) // <---------+
{ // |
return [=] (auto func) // | ???
{ // |
return terminal(func(term)); // >---------+
};
};
作者刚刚声明了一个lambda terminal
,该terminal
接受一个任意参数term
并返回未命名的lambda,仅此而已! 让我们看一下这个未命名的lambda:
func
作为参数,并在复制捕获的参数term
上调用它,并且 func(term)
的结果的terminal的结果; 因此它返回另一个未捕获的lambda来捕获func(term)
的结果,但是现在尚未调用此lambda,因此没有递归。 现在主要的技巧应该更加清楚:
terminal(stdout)
返回捕获了stdout的未命名lambda。 (hello)
将此未命名的lambda称为arg传递给可调用的hello。 这将在先前捕获的标准输出上调用。 hello(stdout)
再次返回stdout,用作对终端的调用的参数,并返回另一个捕获了stdout的未命名lambda。 (world)
与2相同。 terminal(stdout)返回一个带有参数func
函数x
。 所以:
terminal(stdout) ==> x(func) { return terminal(func(stdout)) };
现在terminal(stdout)(hello)调用函数x(hello)
:
terminal(stdout)(hello) ==> x(hello) { return terminal(hello(stdout)) };
这导致hello
函数被调用并再次返回函数x
。
现在terminal(std)(hello)(world)调用函数x(world)
:
terminal(stdout)(hello) ==> x(world) { return terminal(world(stdout)) };
这导致world
函数被调用并再次返回函数x
。 由于不再有参数,现在不再调用函数x
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.