有趣的问题,但我猜没有可接受的 C 解决方案。
为什么这在 C 中是不可能的? (这里有一些猜测)
返回 T 的函数的类型是:
T (*)(void) ;
当然,它期望定义 T...但是,由于 T 是函数本身的类型,因此存在循环依赖关系。
对于结构体 T,我们可以:
struct T ; /* forward declaration */
typedef T * (*f)(void) ; /* f is a function returning a pointer to T */
下一个符号不是很方便吗?
function T ; /* fictional function forward-declaration.
It won't compile, of course */
T T(void) ; /* function declaration */
但由于无法前向声明函数,因此无法使用您在问题中编写的构造。
我不是编译器律师,但我相信这种循环依赖的创建只是因为 typedef 表示法,而不是因为 C/C++ 限制。毕竟,函数指针(我在这里说的是函数,而不是对象方法)都具有相同的大小(以相同的方式结构或类指针都具有相同的大小)。
研究 C++ 解决方案
至于 C++ 解决方案,以前的答案给出了很好的答案(我正在考虑zildjohn01's answer,这里)。
有趣的一点是,它们都基于结构和类可以前向声明的事实(并且在它们的声明体中被认为是前向声明的):
#include <iostream>
class MyFunctor
{
typedef MyFunctor (*myFunctionPointer)() ;
myFunctionPointer m_f ;
public :
MyFunctor(myFunctionPointer p_f) : m_f(p_f) {}
MyFunctor operator () ()
{
m_f() ;
return *this ;
}
} ;
MyFunctor foo() {
std::cout << "foo() was called !" << std::endl ;
return &foo ;
}
MyFunctor barbar() {
std::cout << "barbar() was called !" << std::endl ;
return &barbar ;
}
int main(int argc, char* argv[])
{
foo()() ;
barbar()()()()() ;
return 0 ;
}
哪些输出:
foo() was called !
foo() was called !
barbar() was called !
barbar() was called !
barbar() was called !
barbar() was called !
barbar() was called !
从 C++ 解决方案中获得 C 解决方案的灵感
难道我们不能在 C 中使用类似的方式来获得可比较的结果吗?
不知何故,是的,但结果不像 C++ 解决方案那样性感:
#include <stdio.h>
struct MyFuncWrapper ;
typedef struct MyFuncWrapper (*myFuncPtr) () ;
struct MyFuncWrapper { myFuncPtr f ; } ;
struct MyFuncWrapper foo()
{
printf("foo() was called!\n") ;
/* Wrapping the function */
struct MyFuncWrapper w = { &foo } ; return w ;
}
struct MyFuncWrapper barbar()
{
printf("barbar() was called!\n") ;
/* Wrapping the function */
struct MyFuncWrapper w = { &barbar } ; return w ;
}
int main()
{
foo().f().f().f().f() ;
barbar().f().f() ;
return 0 ;
}
哪些输出:
foo() was called!
foo() was called!
foo() was called!
foo() was called!
foo() was called!
barbar() was called!
barbar() was called!
barbar() was called!
结论
您会注意到 C++ 代码在语义上与 C 代码非常相似:每个源将使用一个结构作为指向函数指针的容器,然后,如果需要,使用包含的指针再次调用它。当然,C++ 解决方案使用 operator() 重载,将符号私有化,并使用特定的构造函数作为语法糖。
(这就是我找到 C 解决方案的方式:尝试“手动”重现 C++ 解决方案)
我不相信我们可以通过使用宏来改进 C 解决方案的语法糖,所以我们坚持使用这个 C 解决方案,我觉得它远非令人印象深刻,但在我找到它的过程中仍然很有趣.
毕竟,寻找奇异问题的解决方案是一种可靠的学习方式……
:-)