从通用容器中检索TProc

7

刚刚发现了一件有趣的事情:

var
  Queue  : TQueue <TProc>;
  MyProc : TProc;
...
MyProc := Queue.Dequeue;

我想你明白这里的意图。然而,编译器认为我想要将 Queue.Dequeue 方法(类型为“对象的过程”)存储在 MyProc 中,并报告错误。

E2010 Incompatible Types: 'TProc' und 'Procedure of object'

我想分享一个解决方法,步骤如下:
MyProc := TProc (Pointer (Queue.Dequeue));

有没有更优雅的解决方案?

第一课:调用函数或过程时,始终添加() ;-) - Jeroen Wiert Pluimers
@Jeroen:呃! 这太像C风格了,不太符合我的口味。更好的教训是编译器应该能够知道需要什么。 此外,正如Rob在我的帖子回复中提到的那样,类型错误了。 Smasher,你应该将此报告为QC中的错误。 - Mason Wheeler
@Mason:编译器无法解决这种歧义,因为它需要向后兼容。这也是其他语言不允许这种歧义的原因之一。是的,我同意,()在开始时看起来很奇怪,但以后你会感激它额外的清晰度。 - Jeroen Wiert Pluimers
考虑到Barry的回答,我不会在QC中报告这个问题。我认为,在编译器无法正确确定类型的罕见情况下使用()是可以的。 - jpfollenius
Smasher,编译器在错误信息中提到的类型实际上是兼容的。编译器报告赋值右侧的类型与方法类型或方法返回类型不匹配。这个问题与任何一种解释是否会产生合法的赋值无关。 - Rob Kennedy
2个回答

11

这里有一些语法歧义,即“Dequeue”名称是指函数本身还是函数的返回值。由于您正在处理可以将普通函数分配给其的匿名方法指针,因此它试图将其解释为函数赋值而不是函数结果赋值。将其强制转换为指针是错误的解决方法,因为这会强制函数赋值通过,然后在尝试调用MyProc时导致各种有趣的错误。

正确的修复方法是消除语法歧义。在Dequeue后面放置一个空括号,以确保编译器确定您正在调用该函数,而不仅仅是通过名称引用它,然后它将正常工作。

MyProc := Queue.Dequeue();

我不确定他想在这里做什么。他是想存储对Queue.Dequeue的引用,以便稍后调用Queue.Dequeue,还是想立即调用Queue.Dequeue并将结果返回并存储到myproc中? - Warren P
嗯,考虑到队列是TProc类型的队列,而MyProc是TProc类型的变量,因此明显意图是获取返回值。 - Mason Wheeler
有趣。刚刚测试了一下,它确实可以工作。不是我预期的,但没问题... - Mason Wheeler
沃伦,我清楚地看到他不想将“Dequeue”的地址分配给变量,因为它没有正确的类型。该方法的类型是“function: TProc of object”,而不是“procedure of object”,所以我有点困惑为什么一开始会出现任何错误。Smasher,要获取该方法的地址,您应该使用Addr(),而不是Pointer(),尽管我们通常拼写为@() - Rob Kennedy
或者如果您想直接运行:Queue.Dequeue()(); - dipold
显示剩余3条评论

6
正如Mason所说,Delphi语法存在歧义。当TFoo.Bar是一个方法时,不清楚FooValue.Bar是否指的是调用TFoo.Bar的结果,还是指一个方法指针(或引用)TFoo.Bar本身(隐含着Self参数为FooValue)。
在Mason的回答评论中,Rob Kennedy似乎建议编译器仅根据所涉及的所有内容的类型来确定这一点。这并不简单;编译器已经做了很多工作,以确定您是要引用方法指针值还是方法调用。当预期接收方是方法指针(或引用、函数指针)类型时,它实际上以不同的方式解析表达式。当重载被考虑时,这项工作特别复杂:编译器扫描每个重载候选项,并检查每个参数位置中是否包含方法指针类型,然后根据该参数位置是否在一个重载中包含函数指针,以不同的方式解析参数。然后,如果没有匹配到期望函数指针的重载,编译器会将解析树从函数指针更改为方法调用。重载机制本身需要在进行值到参数比较时确定要使用哪个。这相当混乱,如果我们不让它更加混乱就太好了。
一个像@或者Addr()这样的前缀式操作符在解决这种歧义方面并没有太大帮助,尤其是因为函数可能会返回函数指针等;你需要多少个@才能禁止隐式(不需要())调用以获取正确的值呢?因此,当引入匿名方法时,对表达式解析进行了更改:我引入了使用()来强制调用的可能性。

您可以在这里阅读更多信息:

http://blog.barrkel.com/2008/03/odd-corner-of-delphi-procedural.html

并在这里:

http://blog.barrkel.com/2008/03/procedurally-typed-expressions-redux.html


1
+1 谢谢!总是很高兴听到为什么以某种方式完成某事的原因。 - jpfollenius

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接