objective c - guia - Tener problemas con el tipo de retorno BOOL en bloques Objective-C
qgis español (3)
Como han dicho otros, la razón por la que está recibiendo el error es que e0 || e1
e0 || e1
devuelve un int
independientemente de los tipos de e0
y e1
. Dado que el compilador infiere el tipo de retorno de bloque basado en la (s) declaración (es) de return
, tiene un bloque que devuelve int
y está intentando asignarlo a una variable de bloque cuyo tipo de retorno de bloque es BOOL
.
Personalmente prefiero esta sintaxis:
BoolBlock bar = ^BOOL { return YES || NO };
para evitar el error, dejando en claro que el tipo de retorno de bloque es BOOL
. El rvalue, un bloque literal, se entiende como un bloque cuyo tipo de retorno es BOOL
y el compilador aplica las conversiones C habituales.
En cuanto a por qué sucede esto, es una decisión de diseño, aunque no parece estar explícitamente documentada. 1 Los bloques son una nueva característica de idioma. Los diseñadores del compilador 2 han decidido que deberían tener una semántica más estricta en los bloques, es decir, la asignación de los tipos de punteros de bloque deben tener tipos estrictamente coincidentes, y aplican esta semántica más estricta cuando asignan un bloque a una variable de bloque, independientemente de que el valor sea un bloque puntero o un bloque literal.
Como no hay bloques de cobertura estándar ISO / IEC en C o C ++, los diseñadores de compiladores son libres de tomar estas decisiones. Apple ha enviado bloques a ISO / IEC JTC1 / SC22 / WG14 como WG14/N1370 y WG14/N1451 y, si lo aceptan, este comportamiento (o alguna variante) debería estandarizarse y documentarse.
1 El código fuente de Clang tiene un comentario que indica que la asignación de punteros de bloque es más estricta que la asignación de punteros de función.
2 Les he preguntado personalmente sobre esto.
Me topé con un curioso problema con el tipo de retorno BOOL
en bloques. Teniendo la siguiente definición:
typedef BOOL (^BoolBlock)(void);
... este código pasa:
BoolBlock foo = ^{ return YES; };
... pero esto no se compila:
BoolBlock bar = ^{ return YES || NO; };
Con el siguiente mensaje de error:
Tipos de punteros de bloque incompatibles que inicializan ''BoolBlock'' (también conocido como ''BOOL (^) (void)'') con una expresión de tipo ''int (^) (void)''
Puedo resolver el problema utilizando un reparto explícito, pero ¿no debería funcionar esto sin él? ¿Hay una solución mejor?
Probablemente estás pensando en el ||
Operador trabaja en idiomas como Ruby y Python, donde regresa en el primer operando que es verdadero. En C, devuelve 1 si cualquiera de los operandos es verdadero y 0 de lo contrario, por eso cree que está devolviendo un entero.
|| El operador devuelve el tipo int como dijo Chuck.
BoolBlock bar = ^{ return (BOOL)(YES || NO); };
o
BoolBlock bar = ^BOOL (void){ return YES || NO; };
BoolBlock bar = ^BOOL (){ return YES || NO; }; // warns in gcc, ok with clang