Можно ли использовать один typedef для определения блока, который не принимает параметров и возвращает блок? - PullRequest
0 голосов
/ 09 февраля 2019

Аналогично / продолжение этого вопроса: Синтаксис для определения блока, который принимает блок и возвращает блок в Objective-C

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

typedef void (^XYZSimpleBlock)(void);
typedef XYZSimpleBlock (^ComplexBlock)(void);

Почему вышеупомянутое допустимо, но это недействительно?

typedef void(^)(void) (^ComplexBlock)(void);

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

Следуя правилу слева-справа C, первый идентификатор не будет ComplexBlock?

typedef void(^)(void) (^ComplexBlock)(void);
// parser reads left right and finds ComplexBlock first

Тогда он пойдет направо и найдет закрытие объявления, затем налево, пока не найдет каретку, затем вправо, чтобы интерпретировать список параметров.

Это подводит нас к

 typedef void(^)(void) (^ComplexBlock)(void);
//       | unhandled   |compiled/interpreted| 

Что происходит в этот момент, когда он не может прочитать void(^)(void) как тип возвращаемого значения?

Меня смущает то, что использование typedef в основном просто#define так не должно ли это быть в основном так же, как указано выше?

typedef void (^XYZSimpleBlock)(void);
same as:
void(^)(void)    
so:
typedef XYZSimpleBlock (^ComplexBlock)(void);
should be the same as:
typedef void(^)(void) (^ComplexBlock)(void);

Я что-то здесь упускаю ...

1 Ответ

0 голосов
/ 09 февраля 2019

Правильный синтаксис:

typedef void (^(^ComplexBlock)(void))(void);

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

Так, например, объявление функции, которая не принимает аргументов и возвращает void:

void a_func(void);

Теперь мы хотим объявить указатель на функцию a_func_ptr, который является указателем на функцию того же типа,Мы хотим, чтобы выражение *a_func_ptr было того же типа, что и a_func, поэтому мы помещаем это выражение в скобках в вышеприведенное и получаем:

void (*a_func_ptr)(void);

Если нам нужен указатель блока вместоуказатель на функцию, мы используем ^ вместо *:

void (^a_block_ref)(void);

(Одна из причин, почему люди находят разочарование синтаксиса блока, состоит в том, что на самом деле никогда не пишется выражение ^a_block_ref для «разыменования» блокапеременная, так что этот скачок неочевиден.)

Взяв вышеизложенное и сделав из него typedef (а не объявление переменной), вы получите:

typedef void (^XYZSimpleBlock)(void);

Но на минутку вернемся к указателю на функцию a_func_ptr.Предположим, вы хотите объявить функцию func_returns_func, которая возвращает указатель на функцию.Вы отбрасываете выражение вызова функции, где a_func_ptr.То есть вы вводите func_returns_func() в:

void (*func_returns_func())(void);

Теперь, когда вы объявляете функции, вам нужно использовать void без аргументов, поэтому вы делаете это:

void (*func_returns_func(void))(void);

Обратите внимание, что вы не собираете и не изолируете тип возврата слева от идентификатора.Он окружает идентификатор.

Теперь вы изменили * на ^, чтобы получить функцию, которая возвращает ссылку на блок вместо указателя функции:

void (^func_returns_block(void))(void);

Давайте сделаемуказатель на функцию, которая возвращает ссылку на блок.Вставьте (*ptr_to_func_returns_block) для func_returns_block и получите:

void (^(*ptr_to_func_returns_block)(void))(void);

Снова замените * на ^, чтобы получить ссылку на блок, который возвращает ссылку на блок:

void (^(^block_returns_block)(void))(void);

И вот мы здесь.Просто измените имя, и вот как вы получите:

void (^(^ComplexBlock)(void))(void);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...