C ++ Синтаксис / Семантика Вопрос: Ссылка на функцию и ключевое слово typedef - PullRequest
7 голосов
/ 02 августа 2011

Для чего будет использоваться typedef int (&rifii) (int, int)?

Что такое typedef перед этим "оператором"?Я хочу думать об этом как

typedef (int (&rifii) (int, int)) [new name]

, но [новое имя] там не так, как если бы вы сделали

typedef int INTEGER;

Подобный вопрос для следующего синтаксиса:

typedef void (*PF) ();

PF edit_ops[ ] = { &cut, &paste, &copy, &search };
PF file_ops[ ] = { &open, &append, & close, &write };

PF* button2 = edit_ops;
PF* button3 = file_ops;

button2[2]( );

Что разрешает typedef?Делается ли это так, что вам не нужно вводить:

void (*PF) ();
(void (*PF) ()) edit_ops[ ] = { &cut, &paste, &copy, &search };
(void (*PF) ()) file_ops[ ] = { &open, &append, & close, &write };

(void (*PF) ())* button2 = edit_ops;
(void (*PF) ())* button3 = file_ops;

Если да, то что произошло со второй частью ([что вы хотите]) typedef, как в:

typedef [what you have -- (FP)] [what you want]

Разъяснение по этому вопросу очень ценится.

Ответы [ 2 ]

17 голосов
/ 02 августа 2011

Typedef не работает как typedef [type] [new name]. Партия [new name] не всегда заканчивается.

Вы должны посмотреть на это так: если [some declaration] объявит переменную, typedef [same declaration] определит тип.

например:.

  • int x; объявляет переменную с именем x типа int -> typedef int x; определяет тип x как int.
  • struct { char c; } s; определяет переменную с именем s некоторого типа структуры -> typedef struct { char c; } s; определяет тип s как некоторый тип структуры.
  • int *p; объявляет переменную p с указателем типа на int -> typedef int *p; определяет тип p как указатель на int.

А также:

  • int A[]; объявляет массив целых чисел с именем A -> typedef int A[]; объявляет тип A как массив целых чисел.
  • int f(); объявляет функцию с именем f -> typedef int f(); объявляет тип функции f как возвращающий int и не имеющий аргументов.
  • int g(int); объявляет имя функции g -> typedef int g(int); объявляет тип функции g как возвращающий int и принимающий одно целое.

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

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

Чтобы создать реальный указатель на функцию, мы должны добавить '*' к имени. Что, к сожалению, имеет неправильный приоритет:

  • typedef int *pf(); объявляет тип функции pf как возвращающий int *. К сожалению, это не то, что было задумано.

Поэтому используйте () для группировки:

  • typedef int (*pf)(); объявляет тип указателя на функцию pf как возвращающий int и не имеющий аргументов.
  • typedef int (&rf)(); объявляет ссылочный тип функции rf как возвращающий int и не принимающий аргументов.

Давайте теперь посмотрим на ваши примеры и ответим на ваши вопросы:

typedef int (&rifii) (int, int); объявляет ссылочный тип функции rifii как возвращающий int и принимающий два аргумента int.

И очевидно (?) button2[2]( ); позвонит copy();.

Правильный синтаксис без typedefs трудно написать правильно без компилятора и трудно читать даже с помощью компилятора:

void (*edit_ops[])() = { &cut, &paste, &copy, &search }; 
void (*file_ops[])() = { &open, &append, & close, &write };

void (**button2)() = edit_ops;
void (**button3)() = file_ops;

button2[2]( );   

Именно поэтому все предпочитают typedefs при использовании указателей на функции.

При чтении найдите место для начала чтения. Прочитайте как можно больше вправо, но соблюдайте группировку по (). Затем прочитайте как можно больше влево, снова ограниченный группировкой (). Закончив все внутри (), начните с чтения справа, затем слева.

Применительно к void (*edit_ops[])(), это означает, что

  1. edit_ops is (идите направо)
  2. массив (нажмите на конец группы, поверните налево)
  3. указателя (конец группировки)
  4. к функции, принимающей (разбор () справа)
  5. без аргументов (идите налево)
  6. возвращение пустоты

Для экспертов: Чтобы сделать его еще более сложным, аргументы могут иметь имена (которые будут игнорироваться), поэтому даже может быть трудно найти, с чего начать анализ! Например. typedef int (*fp)(int x); допустимо и соответствует typedef int (*fp)(int); Имена могут даже иметь () вокруг них: typedef int (*fp)(int (x)); Но, как мы видели, имена аргументов могут быть опущены, поэтому допускается даже следующее: typedef int (*fp)(int ());. Это по-прежнему указатель на функцию, принимающий одно целое и возвращающий целое число. Если вы хотите сделать ваш код действительно трудным для чтения ...

0 голосов
/ 02 августа 2011

edit: извините, первый ответ не инициализировал fcn ptr.

typedef int (& rifii) (int, int) позволяет вам объявить указатели на функции, которые возвращают int по ссылке, и принимают два целых числа как параметры.

    rifi x,y,z;

int &ret_an_int_ref( int p1, int p2 ) { 
    static int retval=0;
    if( p1 > p2 ) retval = p1*p2;
    return retval;
}

    x = ret_an_int_ref;
    y = ret_an_int_ref;

int & an_int_ref = x(1,2);
int & another_int_ref=y(3,4);

z = x;

z(1,2); // will give the same answer as x(1,2);
...