什么类型的T使以下代码可编辑?
T f(){ return &f; }
我更喜欢C答案,但我将问题标记为C和C ++,以防只有使用模板的答案。
答案 0 :(得分:9)
我希望这不是作弊(仅限C ++):
class T {
private:
T (*_func)();
public:
T(T (*func)()) : _func(func) {}
T operator()() {
return *this;
}
};
T f() { return &f; }
int main() {
f()()()()()()()();
}
答案 1 :(得分:9)
有趣的问题,但我猜是没有可接受的C解决方案。
返回T的函数的类型是:
T (*)(void) ;
当然,期待T被定义......但是,由于T是函数本身的类型,因此存在循环依赖。
对于struct 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 ++解决方案,以前的答案给出了很好的答案(我在考虑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 ++解决方案那样性感:
#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解决方案,我发现这个解决方案远非令人印象深刻,但在我找到它的时候仍然很有趣
毕竟,搜索奇怪问题的解决方案是一种可靠的学习方法......
: - )
答案 2 :(得分:4)
正如C FAQ Question 1.22所解释的那样,这在C语言中是不可能的。变通办法包括将函数指针包装在struct
中并返回该函数指针或返回另一个(任意)函数指针类型,这可以作为函数之间的转换指针类型保证无损。
答案 3 :(得分:2)
好笑,我最近一直在考虑这个问题(只是我希望函数能够将指针指向自身而不是返回它)。
对于C ++,你已经得到了zildjohn01的答案。
如果我们坚持使用标准C,那么就没有完全按照书面编译的解决方案。您可以使用显式转换将其拉出 - void*
将无效,因为函数指针到数据指针的转换不符合标准,但您可以使用任何其他函数指针类型(例如{{1可以) - 标准明确允许从任何函数指针类型转换为任何其他函数类型并返回,并保证您将获得原始值。
答案 4 :(得分:1)
这个问题的答案只会花费你永恒的灵魂。
答案 5 :(得分:0)
在C ++中,简单:
struct my_function {
my_function& operator()() {
return *this;
}
};
在C中,你必须抛出void * s,这将在任何合理的实现中起作用,但我相信在技术上是未定义的。
如果两种语言都允许简单的递归类型,那将是很好的。唉,他们没有。
答案 6 :(得分:0)
没有类型可以兼容,因为你在typedef中会有无限递归。
然而,有可能像DrPizza那样去模拟它。但是,你永远不会真的这样做。由auto / decltype的奇迹支持:
auto f() -> decltype(&f) { return &f; } = a shitload of errors.
答案 7 :(得分:0)
没有理由说C编译器后端不应该能够处理它,并且幸运的前端(除了解析器和符号解析传递)也可以。但是,定义C的方式使得将数据提供给编译器的后期位置是不可能的。 OTOH是一个C编译器,它通过引用实现typdef,并且在解析它们使用的符号之前不足以将typedef填充到符号表中,实际吞下它就好了。