インターネット掲示板を閲覧すると、この小さな課題に遭遇しました。
「好きな言語で再帰的な無名関数を実装する」
明らかに、これはstd :: function/functionポインターを使用して簡単です。
私が本当に興味を持っているのは、ラムダを識別子にバインドせずにこれが可能かどうかです。
(明らかな無限再帰を無視して)次のようなもの:
[](){ this(); }();
もちろん、C ++では、関数を呼び出すには、構文上の制約のために、関数をどこかの識別子にバインドする必要があります。ただし、パラメーターに十分な名前が付けられていないものとして受け入れる場合は、「名前が付けられていない」状態で適切に繰り返されるバージョンのy-combinatorをC++で作成することができます。
再帰的なラムダに対してtypedefを実行する方法がわからないため、これは本当に醜いです。したがって、キャストの乱用を多く使用します。ただし、動作し、FLY!!
スタックオーバーフローが原因でsegfaultが発生するまで印刷されます。
#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);
});
}
2つのラムダは、どちらも明示的にどこにも名前が割り当てられていないという意味で名前が付けられていません。2番目のラムダは実際の主力製品であり、基本的には最初のラムダを使用して自身を呼び出し、パラメーターの形式で自身への参照を取得します。
これを使用して「便利な」作業を行う方法は次のとおりです。
#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(); }();
}
それは再帰的です-間接的に、少なくとも。
そうでなければ、いいえ、名前を割り当てずにラムダ自体を参照する方法はありません。
関数/メソッドの識別子がありません、十分に近いかどうか!?
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オフセットを思いついたのですが、なぜこの値なのか説明できれば素晴らしいと思います。