Как объявить указатель функции, который возвращает указатель на функцию

Как вы объявляете указатель на функцию, которая указывает на функцию с теми же параметрами, а также возвращает указатель на функцию с теми же параметрами.

т.е. funcPtr указывает на func1(int a, int b), а func1 возвращает указатель на другую функцию func2(int a, int b). func2 также возвращает указатель на функцию с той же сигнатурой, что и func1.

TYPE funcPtr = func1;
funcPtr = funcPtr(0, 1);

Как объявить funcPtr? Каким должен быть TYPE?

Ответы

Ответ 1

Неразрешимая самооценка

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

typedef funcType (*funcType)(void);

Вернуть struct

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

struct func {
    struct func (*func) (void);
};

struct func foo (void);
struct func bar (void);

struct func foo (void) { return (struct func){ bar }; }
struct func bar (void) { return (struct func){ foo }; }

...
    struct func funcPtr = { foo };
    funcPtr = funcPtr.func();

Возвращает другой тип указателя функции

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

typedef void (*funcPtrType)(void);
typedef funcPtrType funcType(void);

funcType foo;
funcType bar;

funcPtrType foo (void) { return (funcPtrType)bar; }
funcPtrType bar (void) { return (funcPtrType)foo; }

...
    funcType *p = foo;
    p = (funcType *)p();

Возврат индекса

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

enum funcEnum { fooEnum, barEnum };
typedef enum funcEnum (*funcType)(void);

enum funcEnum foo (void) { return barEnum; }
enum funcEnum bar (void) { return fooEnum; }

funcType funcTable[] = { [fooEnum] = foo, [barEnum] = bar };

...
    funcType p = funcTable[fooEnum];
    p = funcTable[p()];

Это было поднято в комментариях и в ответе Павла, но представлено здесь для полноты.

Ответ 2

Это только пример без typedefs. Вы можете попытаться изменить параметры функций, но синтаксис ужасен и обычно бесполезен.

char (*(*((*foo)()))())()

foo - указатель на функцию, возвращающую указатель на функцию, возвращающую указатель на функцию, возвращающую символ

Или вы можете использовать typedefs

например

typedef int (*foo2)(int, int);

typedef foo2 (*foo1)(int, int);
typedef foo1 (*foo)(int, int);

или более общий

typedef int (*foo'n')(int, int);
typedef foo'n' (*foo'n-1')(int, int);

...

typedef foo2 (*foo1)(int, int);
typedef foo1 (*foo)(int, int);

Ответ 3

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

Ниже приведено несколько шагов в таком бесконечном объявлении, чтобы показать, как декларация расширяется и расширяется:

int f0(int a) {
    return 1;
}
int (*f1(int a))(int) {
    return f0;
}
int (*(*f2(int a))(int))(int) {
    return f1;
}


В качестве решения для устаревшего кода он может возвращать номер состояния, а таблица с функциями может использоваться для вызова функции, определенной для состояния, например:
#define STATE0 0
#define STATE1 1

int fx1(int a);
int fx2(int a);

int (*ftab[])(int) = {
    fx1,
    fx2
};

void examplefunc(void)
{
    int x = ftab[STATE1](3);  // example of calling function from table
}