Подтвердить что ты не робот

Как написать указатель функции на функцию, возвращающую функцию указателя на функцию?

Я хочу назначить адрес функции указателю на функцию, но функция, которая будет адресована, возвращает указатель на функцию с той же самой сигнатурой, что и сама, заставляя ее перезаписывать так, чтобы я не мог писать тип возврата вообще, для указателя функции или даже самого объявления функции...

Я предполагаю способ упрощения проблемы, поэтому не путать:

Как я могу написать объявление функции такое, чтобы он мог вернуть указатель на себя (или любую другую функцию с той же сигнатурой)?

????? function(int a){
    // could be this function, or another with the same signature, 
    return arbitraryFunction;  
}

?????(*func)(int) = function;  // same problem as above

изменить

Пока у меня есть решение, хотя я не буду публиковать его как ответ, потому что он агрессивно уродлив. Он избавляется от рекурсии, просто возвращая указатель raw void* в качестве возвращаемого типа и заканчивая тем, что принимает следующую форму:

void* function(int parameter){
    return arbitraryFunction; // of the same signature
}

void*(*func)(int) = function; 
func = reinterpret_cast<void*(*)(int)>(func(42));  // sin

edit2:

Кажется, что литье между указателями функций и регулярными указателями - UB, поэтому я не могу использовать void* в этом случае...

Чтобы ответить на один из комментариев, это для передачи управления между несколькими "главными" циклами в моей программе, причем каждый цикл получает свою собственную функцию. Там много способов сделать это, но возврат указателей функций (или NULL для завершения программы) в середине цикла казался простейшим методом, но я не ожидал, что указатели на данные и указатели на адреса функций будут несовместимы с каждым Другие. Я думаю, что возвращение объектов полиморфной функции в конечном итоге станет более разумным вариантом.

4b9b3361

Ответ 1

Не используйте void*, потому что не гарантируйте, что void * может содержать указатель на функцию. Вы можете использовать void(*)() как обходной путь:

typedef void(*void_func)();
typedef void_func (*func_type) (int);
void_func arbitraryFunction(int a) {
    // could be this function, or another with the same signature, 
    cout << "arbitraryFunction\n";
    return nullptr;  
}
void_func function(int a) {
    // could be this function, or another with the same signature, 
    return (void_func) arbitraryFunction;  
}
int main() {
    // your code goes here
    func_type f = (func_type) function(0);
    f(0);
    return 0;
}

LIVE

C99 [6.2.5/27]:

Указатель на void должен иметь те же требования к представлению и выравниванию, что и указатель на тип символа. Аналогично, указатели на квалифицированные или неквалифицированные версии совместимых типов должны иметь те же требования к представлению и выравниванию. Все указатели на типы структуры должны иметь одинаковое представление и выравнивание как друг друга. Все указатели на типы профсоюзов должны иметь те же требования к представлению и выравниванию как друг друга. указатели для других типов не обязательно иметь такое же представление или выравнивание требования.

C99 [6.3.2.3/8]:

Указатель на функцию одного типа может быть преобразован в указатель на функцию другого типа и обратно; результат сравним равный исходному указателю.

Ответ 2

Трюк в C заключается в том, чтобы использовать тот факт, что любой вид указателя функции может быть добавлен к любому другому указателю функции:

#include <stdlib.h>
#include <stdio.h>

typedef void(*emptyfunc)(void);
typedef emptyfunc (*funcptr2)(int);

funcptr2 strategy(int m)
{
  printf("Strategy %d.\n", m);
  return (funcptr2)&strategy;
}

int main (void)
{
  const funcptr2 strategy2 = (funcptr2)strategy(1);
  const funcptr2 strategy3 = (funcptr2)strategy2(2);
  strategy3(3);

  return EXIT_SUCCESS;
}

Каждый указатель на стратегию всегда находится в типе, который можно вызывать один раз, а возвращаемое значение возвращается в форму, которая может быть вызвана еще раз.

В С++ вы объявите объект функции:

class strategy {
  public:
  virtual const strategy& operator()(int) const = 0;
}

Экземпляр этого класса можно вызвать как функцию.

Ответ 3

Я подозреваю, что вы пытаетесь сделать более сложную версию чего-то вроде этого:

typedef MainLoop *MainLoop(); // not legal

extern MainLoop* main_loop_1();
extern MainLoop* main_loop_2();

MainLoop* main_loop_1()
{
    // do some work here
    return main_loop_2;
}

MainLoop* main_loop_2()
{
    // do some work here
    return main_loop_1;
}

int main()
{
    MainLoop f = main_loop_1;

    for (;;) {
      f = f();
    }
}

Обходной путь заключается в том, чтобы обернуть указатель функции в struct:

struct MainLoop {
    MainLoop (*function_ptr)(); // legal
};

extern MainLoop main_loop_1();
extern MainLoop main_loop_2();

MainLoop main_loop_1()
{
    // do some work here
    return {main_loop_2};
}

MainLoop main_loop_2()
{
    // do some work here
    return {main_loop_1};
}  

int main()
{
    MainLoop f{main_loop_1};

    for (;;) {
       f = f.function_ptr();
    }
}