รหัสของคุณใช้ไม่ได้ แต่สิ่งนี้ทำ:
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 ก็โอเคแน่นอน
การแก้ไข:
[&](auto self) {
return [self,&a](auto b) {
std::cout << (a + b) << std::endl;
return self(self);
};
};
รหัสยังคงมีรูปแบบไม่ถูกต้อง เพื่อดูสิ่งนี้เราสามารถขยาย lambdas:
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 ++ ไม่สนใจเมื่อหักล้างประเภทผลตอบแทน เพียงแค่ตรวจสอบโค้ดทีละบรรทัด
และ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