ठीक है, आपका कोड काम नहीं करता है। लेकिन यह करता है:
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
आपका कोड यूबी और बीमार दोनों तरह का है, इसके लिए किसी निदान की आवश्यकता नहीं है। जो मजाकिया है; लेकिन दोनों को स्वतंत्र रूप से तय किया जा सकता है।
सबसे पहले, यूबी:
auto it = [&](auto self) { // outer
return [&](auto b) { // inner
std::cout << (a + b) << std::endl;
return self(self);
};
};
it(it)(4)(5)(6);
यह यूबी है क्योंकि बाहरी self
मूल्य से लेता है, फिर आंतरिक self
संदर्भ द्वारा कैप्चर करता है, फिर outer
रनिंग खत्म होने के बाद इसे वापस करने के लिए आगे बढ़ता है । तो segfaulting निश्चित रूप से ठीक है।
जोड़:
[&](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 ++ रिटर्न प्रकारों को कम करते समय ध्यान नहीं देता है; यह बस लाइन लाइन कोड की जाँच करता है।
और 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 का उपयोग करें।