以下递归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;
}
Run Code Online (Sandbox Code Playgroud)
我在这里错过了什么?
Nim*_*Nim 45
这不是一个递归函数调用,一步一步看一下:
terminal(stdout) - 这只是返回已捕获的lambda stdouthello执行lambda(func(term)),其结果传递给terminal()它,它只返回lambda,如1所示.world,它与2相同,这次返回值被丢弃...Mik*_*our 26
调用本身不是递归的.它返回一个函数对象,如果被调用,它将terminal再次调用以生成另一个函数对象.
因此terminal(stdout)返回一个捕获的函子,stdout可以用另一个函数对象调用.再次调用它,用捕获的术语(hello)调用hello仿函数stdout,输出"Hello"; 调用terminal并返回另一个函子,这次捕获的返回值hello- 仍然是stdout.调用该仿函数,(world)再次输出相同的函数"World".
Mar*_* A. 13
这里的关键是要明白这是有效的:
world(hello(stdout));
Run Code Online (Sandbox Code Playgroud)
并将打印"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;
}
Run Code Online (Sandbox Code Playgroud)
Pio*_*cki 10
它可以在内部翻译成如下内容:
#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);
}
Run Code Online (Sandbox Code Playgroud)
实际上这就是编译器在 lambdas 场景背后所做的事情(有一些近似).
我认为混淆的来源是将lambda声明读作lambda调用.确实在这里:
auto terminal = [](auto term) // <---------+
{ // |
return [=] (auto func) // | ???
{ // |
return terminal(func(term)); // >---------+
};
};
Run Code Online (Sandbox Code Playgroud)
作者刚刚声明了一个lambda terminal,它接受一个任意参数term并返回一个未命名的lambda,仅此而已!让我们来看看这个未命名的lambda,它:
func作为参数并调用它在副本上捕获的参数term和func(term); 所以它返回另一个未命名的lambda来捕获结果func(term),但是这个lambda现在不被调用,没有递归.现在主要的诀窍应该更清楚:
terminal(stdout) 返回一个未命名的lambda,它捕获了stdout.(hello)将此未命名的lambda称为arg hello callable.这在先前捕获的stdout上被调用.hello(stdout)再次返回stdout,它被用作对终端的调用的参数,返回另一个未命名的lambda,它捕获了stdout.(world) 与2相同.| 归档时间: |
|
| 查看次数: |
4215 次 |
| 最近记录: |