글쎄, 코드가 작동하지 않습니다. 그러나 이것은 :
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);
외부는 self
값을 취하고 내부는 self
참조로 캡처 한 다음 나중에 반환 하기 때문에 이것은 UB입니다.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를 사용하십시오.