我试图通过Y-combinator在C++中引用函数名来编写递归.但是,我无法在以下尝试中找出函数的类型:
#include <iostream>
using std::cin;
using std::cout;
template<class Function> unsigned long factorial1(Function self, unsigned long n) {
return n ? n * self(self, n - 1) : 1;
}
unsigned long factorial(unsigned long n) {
return factorial1(factorial1, n);
}
int main() {
unsigned long n;
cin >> n;
cout << factorial(n) << '\n';
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译器不能推断出什么是Function,我也不能.然后我尝试了以下内容:
#include <iostream>
using std::cin;
using std::cout;
struct Factorial {
template<class Function> unsigned long operator()(Function self, unsigned long n) const {
return n ? n * self(self, n - 1) : 1;
}
};
unsigned long factorial(unsigned long n) {
return Factorial()(Factorial(), n);
}
int main() {
unsigned long n;
cin >> n;
cout << factorial(n) << '\n';
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这与上面的例子相比,不同之处在于我将工作函数更改为可调用对象,这Function可以很容易地推导出来Factorial,从而导致组合器的以下完整实现:
#include <iostream>
using std::cin;
using std::cout;
struct Factorial {
template<class Function> unsigned long operator()(Function self, unsigned long n) const {
return n ? n * self(self, n - 1) : 1;
}
};
template<class Function> auto y(Function f) {
return [f](auto n) {
return f(f, n);
};
}
int main() {
unsigned long n;
cin >> n;
cout << y(Factorial())(n) << '\n';
return 0;
}
Run Code Online (Sandbox Code Playgroud)
问题是,是否可以将结构重写Factorial为普通函数?
小智 -1
在我看来,您所描述的情况类似于无限类型或递归类型。如果您尝试自己手动推导类型,您会发现它是无限的,您也可能自己发现了这一点。为了表明这一点,我想将您的factorial1功能简化为:
template <class T> void foobar(T self) {
self(self);
}
Run Code Online (Sandbox Code Playgroud)
然后尝试使用函数指针而不是模板来编写此函数,以手动推断其类型。
首先,我们希望它foobar以函数指针作为参数。
void foobar(void (*self)());
^^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)
但这仍然不是我们想要的,这个函数指针应该将指向自身的指针作为参数。
void foobar(void (*self)(void (*)()));
^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)
但我们还没有完成,因为我们必须再次添加一个指向自身的指针作为参数
void foobar(void (*self)(void (*)(void (*)())));
^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)
你可以看到这种模式是如何持续下去的。
void foobar(void (*self)(void (*)(void (*)(void (*)()))));
^^^^^^^^^^
void foobar(void (*self)(void (*)(void (*)(void (*)(void (*)())))));
^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)
你给出的例子,你设法用一个结构来做到这一点,只是通过模仿它operator()。如果将该函数的名称更改为foobar如下所示:
struct Factorial {
template<class Function> unsigned long foobar(Function self, unsigned long n) const {
return n ? n * self.foobar(self, n - 1) : 1;
}
};
unsigned long factorial(unsigned long n) {
return Factorial().foobar(Factorial(), n);
}
Run Code Online (Sandbox Code Playgroud)
因此,您基本上foobar在 中 递归地调用foobar,这与您最初的声明相矛盾,即您希望在不知道/引用函数名称的情况下调用该函数。