2011-05-09 46 views
22

我偶然发现了一个好奇的问题,返回类型为BOOL。具有以下定义:在Objective-C块中遇到BOOL返回类型问题

typedef BOOL (^BoolBlock)(void); 

...此代码将:

BoolBlock foo = ^{ return YES; }; 

...但是这无法编译:

BoolBlock bar = ^{ return YES || NO; }; 

,出现以下错误信息:

不兼容的块指针类型 初始化 'BoolBlock'(又名 'BOOL (^)(无效)')与类型的 '诠释(^)(无效)'

我可以使用显式转换解决问题的表达,但没有它,这不应该工作吗?有更好的解决方案吗?

回答

11

您可能认为||运算符使用Ruby和Python等语言工作,它在第一个操作数truthy中返回。在C中,如果两个操作数都是真的,则返回1,否则返回0 - 这就是为什么它认为你返回一个整数。

+3

那么为什么像' - (BOOL)foo {return YES ||没有; }'编译?换句话说,为什么区分大小写和[BOOL](http://stackoverflow.com/questions/541289)区分大小写而不是函数? – zoul 2011-05-09 09:00:14

+2

@zoul:该函数有一个明确的返回类型,所以int将被隐式转换为BOOL。但是你创建的块没有明确的返回类型,所以它会从返回语句中推断出它的返回类型(这是块的特殊功能)。你返回一个int,所以它推断该块返回一个int。只有在块的类型被完全推断之后,编译器才会根据要分配的变量的类型检查该类型,以便获得类型不匹配。 – Chuck 2011-05-09 19:38:22

15

|| Chuck说,操作符返回int类型。

BoolBlock bar = ^{ return (BOOL)(YES || NO); }; 

BoolBlock bar = ^BOOL (void){ return YES || NO; }; 
BoolBlock bar = ^BOOL(){ return YES || NO; }; // warns in gcc, ok with clang 
+1

谢谢,在块定义中声明返回类型有帮助,它比返回之前的强制类型更好。 Clang对'^ BOOL(){...}'很满意。 – zoul 2011-05-09 09:04:52

+1

谢谢!我遇到了同样的问题,我尝试使用... = BOOL ^而不是... =^BOOL – ribeto 2011-10-19 19:10:41

5

正如其他人所指出的,你得到错误的原因是e0 || e1类型无关的e0e1的返回int。由于编译器根据return语句推断块返回类型,因此您有一个返回int的块,并且您试图将其分配给块返回类型为BOOL的块变量。

我个人比较喜欢这种语法:

BoolBlock bar = ^BOOL { return YES || NO }; 

,以避免错误,并明确该块返回类型为BOOL。块右值rvalue被理解为返回类型为BOOL的块,编译器应用通常的C转换。至于为什么发生这种情况,这是一个设计决定,虽然它似乎没有明确记录。 块是一种新的语言功能。编译器设计人员已经决定它们应该在块上具有更紧密的语义 - 即块指针类型的分配必须具有严格匹配的类型 - 并且在将块分配给块变量时强制执行这些更严格的语义,而不管r值是一个块指针或一个块文字。

由于目前还没有涵盖C或C++中的块的ISO/IEC标准,因此编译器设计人员可以自由做出这些决定。苹果已将ISO/IEC JTC1/SC22/WG14的块提交为WG14/N1370WG14/N1451,并且如果他们接受它,则应该对此行为(或其某种变体)进行标准化和记录。

Clang的源代码确实有一个注释,指出块指针的赋值比赋值函数指针更严格。

我亲自问过他们这件事。

+0

^BOOL {}有效吗?看起来[区块概述](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1370.pdf)和[区块建议](http://www.open-std。 org/jtc1/sc22/wg14/www/docs/n1451.pdf)不提这样的记号。只有^ void(void){},^(void){}和^ {}。 – 2011-05-10 00:32:18

+0

@Kazuki建议说'有空的参数列表的闭包可以通过声明它为(void)或完全省略(void)来指定它。' – 2011-05-10 00:36:53

+0

@Kazuki感谢您的建议链接! – 2011-05-10 00:37:06