Nah, kode Anda tidak berfungsi. Tapi ini memang:
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>;
Kode tes:
ycombinator bob = {[x=0](auto&& self)mutable{
std::cout << ++x << "\n";
ycombinator ret = {self};
return ret;
}};
bob()()(); // prints 1 2 3
Kode Anda adalah UB dan berformat buruk, tidak diperlukan diagnostik. Yang lucu; tetapi keduanya bisa diperbaiki secara independen.
Pertama, UB:
auto it = [&](auto self) { // outer
return [&](auto b) { // inner
std::cout << (a + b) << std::endl;
return self(self);
};
};
it(it)(4)(5)(6);
ini adalah UB karena bagian luar diambil self
oleh nilai, kemudian bagian dalam ditangkap self
dengan referensi, kemudian dilanjutkan untuk mengembalikannya setelah outer
selesai dijalankan. Jadi segfaulting sudah pasti ok.
Cara mengatasinya:
[&](auto self) {
return [self,&a](auto b) {
std::cout << (a + b) << std::endl;
return self(self);
};
};
Kode tetap berbentuk buruk. Untuk melihat ini, kami dapat memperluas lambda:
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);
ini contoh __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;
};
Jadi selanjutnya kita harus menentukan jenis kembalian __outer_lambda__::operator()
.
Kami melewatinya baris demi baris. Pertama kita buat __inner_lambda__
tipe:
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;
};
Sekarang, lihat di sana - jenis kembaliannya adalah self(self)
, atau __outer_lambda__(__outer_lambda__ const&)
. Tapi kami sedang mencoba menyimpulkan jenis pengembalian __outer_lambda__::operator()(__outer_lambda__)
.
Anda tidak diizinkan melakukan itu.
Meskipun pada kenyataannya tipe kembalian __outer_lambda__::operator()(__outer_lambda__)
sebenarnya tidak bergantung pada tipe kembalian __inner_lambda__::operator()(int)
, C ++ tidak peduli saat mengurangi tipe kembalian; itu hanya memeriksa kode baris demi baris.
Dan self(self)
digunakan sebelum kami menyimpulkannya. Program yang buruk.
Kita bisa menambalnya dengan bersembunyi self(self)
sampai nanti:
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);
}
dan sekarang kodenya benar dan terkompilasi. Tapi saya pikir ini sedikit hack; cukup gunakan ycombinator.