Интересная проблема, но без приемлемого решения 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 здесь).
Интересно, что все они основаны натот факт, что структуры и классы могут быть заранее объявлены (и считаются заранее объявленными в их теле объявления):
#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, которое, как мне кажется, далеко не впечатляет, но все жебудучи интересным в то время, когда мне потребовалось найти его.
В конце концов, поиск решений странных проблем - верный способ узнать ...
: -)