まあ、あなたのコードは機能しません。しかし、これは:
template<class F>
struct ycombinator {
F f;
template<class...Args>
auto operator()(Args&&...args){
return f(f, std::forward<Args>(args)...);
}
};
template<class F>
ycombinator(F) -> ycombinator<F>;
テストコード:
ycombinator bob = {[x=0](auto&& self)mutable{
std::cout << ++x << "\n";
ycombinator ret = {self};
return ret;
}};
bob()()(); // prints 1 2 3
コードはUBであり、形式が正しくないため、診断は必要ありません。面白いです。ただし、どちらも個別に修正できます。
まず、UB:
auto it = [&](auto self) { // outer
return [&](auto b) { // inner
std::cout << (a + b) << std::endl;
return self(self);
};
};
it(it)(4)(5)(6);
これはUBです。外側がself
値で取得self
し、次に内側が参照でキャプチャし、outer
実行が終了した後に戻ります。したがって、segfaultingは間違いなくOKです。
修正:
[&](auto self) {
return [self,&a](auto b) {
std::cout << (a + b) << std::endl;
return self(self);
};
};
コードは不正な形式のままです。これを確認するには、ラムダを展開します。
struct __outer_lambda__ {
template<class T>
auto operator()(T self) const {
struct __inner_lambda__ {
template<class B>
auto operator()(B b) const {
std::cout << (a + b) << std::endl;
return self(self);
}
int& a;
T self;
};
return __inner_lambda__{a, self};
}
int& a;
};
__outer_lambda__ it{a};
it(it);
これはインスタンス化します__outer_lambda__::operator()<__outer_lambda__>
:
template<>
auto __outer_lambda__::operator()(__outer_lambda__ self) const {
struct __inner_lambda__ {
template<class B>
auto operator()(B b) const {
std::cout << (a + b) << std::endl;
return self(self);
}
int& a;
__outer_lambda__ self;
};
return __inner_lambda__{a, self};
}
int& a;
};
したがって、次にの戻り値の型を決定する必要があり__outer_lambda__::operator()
ます。
行ごとに説明します。まず、__inner_lambda__
タイプを作成します。
struct __inner_lambda__ {
template<class B>
auto operator()(B b) const {
std::cout << (a + b) << std::endl;
return self(self);
}
int& a;
__outer_lambda__ self;
};
さて、そこを見てください。戻り値の型はself(self)
、または__outer_lambda__(__outer_lambda__ const&)
です。しかし、私たちはの戻り値の型を推測しようとしてい__outer_lambda__::operator()(__outer_lambda__)
ます。
あなたはそれをすることはできません。
実際にはの戻り値の型はの戻り値の型に__outer_lambda__::operator()(__outer_lambda__)
実際には依存して__inner_lambda__::operator()(int)
いませんが、C ++は戻り値の型を推定するときに気にしません。コードを1行ずつチェックするだけです。
そして、self(self)
それを推定する前に使用されます。不良プログラム。
self(self)
後で非表示にすることで、これにパッチを適用できます。
template<class A, class B>
struct second_type_helper { using result=B; };
template<class A, class B>
using second_type = typename second_type_helper<A,B>::result;
int main(int argc, char* argv[]) {
int a = 5;
auto it = [&](auto self) {
return [self,&a](auto b) {
std::cout << (a + b) << std::endl;
return self(second_type<decltype(b), decltype(self)&>(self) );
};
};
it(it)(4)(6)(42)(77)(999);
}
そして今、コードは正しく、コンパイルされます。しかし、これはちょっとしたハックだと思います。ycombinatorを使用してください。