浏览一些互联网板我遇到了这个小挑战:
“用你喜欢的语言实现一个递归匿名函数”
显然,使用 std::function/function 指针很容易。
我真正感兴趣的是,如果不将 lambda 绑定到标识符,这是否可行?
类似的东西(忽略明显的无限递归):
[](){ this(); }();
当然,在 C++ 中,要调用任何函数,您必须将其绑定到某处的标识符,这仅仅是由于语法限制。但是,如果您接受参数足够未命名,则可以在 C++ 中创建一个 y-combinator 版本,该版本可以很好地递归而无需“命名”。
现在,这真的很难看,因为我不知道如何为递归 lambda 做 typedef。所以它只是使用了很多演员滥用。但是,它可以工作并打印,FLY!!
直到由于堆栈溢出而出现段错误。
#include <iostream>
typedef void(*f0)();
typedef void(*f)(f0);
int main() {
[](f x) {
x((f0)x);
} ([](f0 x) {
std::cout<<"FLY!!\n";
((f)x)(x);
});
}
这两个 lambda 表达式是未命名的,因为它们都没有被显式分配给任何地方的名称。第二个 lambda 是真正的主力,它基本上通过使用第一个 lambda 以参数的形式获取对自身的引用来调用自身。
以下是您将如何使用它来做一些“有用的”工作:
#include <iostream>
typedef int param_t;
typedef int ret_t;
typedef void(*f0)();
typedef ret_t(*f)(f0, param_t);
int main() {
/* Compute factorial recursively */
std::cout << [](f x, param_t y) {
return x((f0)x, y);
} ([](f0 x, param_t y) {
if(y == 0)
return 1;
return y*((f)x)(x, y-1);
}, 10) << std::endl;
}
你被允许作弊吗?
void f(){
[]{ f(); }();
}
它是递归的——至少是间接的。
否则,不,没有办法在不给它命名的情况下引用 lambda 本身。
没有功能/方法的标识符,是否足够接近!?
struct A
{
void operator()()
{
[&]()
{
(*this)();
}();
}
};
打电话
A{}(); // Thanks MooningDuck
我似乎想出了自己的解决方案:
#include <iostream>
int main()
{
std::cout<<"Main\n";
[&](){
std::cout<<"Hello!\n";
(&main+13)();
}();
}
第一次调用 cout 只是为了表明它没有调用 main。
我通过反复试验得出了 13 个偏移量,如果有人能解释为什么它是这个值,那就太好了。