Как написать указатель функции на функцию, возвращающую функцию указателя на функцию?
Я хочу назначить адрес функции указателю на функцию, но функция, которая будет адресована, возвращает указатель на функцию с той же самой сигнатурой, что и сама, заставляя ее перезаписывать так, чтобы я не мог писать тип возврата вообще, для указателя функции или даже самого объявления функции...
Я предполагаю способ упрощения проблемы, поэтому не путать:
Как я могу написать объявление функции такое, чтобы он мог вернуть указатель на себя (или любую другую функцию с той же сигнатурой)?
????? 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 для завершения программы) в середине цикла казался простейшим методом, но я не ожидал, что указатели на данные и указатели на адреса функций будут несовместимы с каждым Другие. Я думаю, что возвращение объектов полиморфной функции в конечном итоге станет более разумным вариантом.
Ответы
Ответ 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();
}
}