【问题标题】:Retrieve TProc from Generic Container从通用容器中检索 TProc
【发布时间】:2011-01-17 21:09:34
【问题描述】:

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

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));

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

【问题讨论】:

  • 第 1 课:调用函数或过程时总是加 () ;-)
  • @Jeroen:呃!太像我的口味了。更好的教训:编译器应该能够说出这里想要什么。此外,正如 Rob 在他对我的帖子的回复中提到的,它的类型错误。 Smasher,您应该将此作为 QC 中的错误报告。
  • @Mason:编译器不能,因为它需要向后兼容这种歧义。这是其他语言不允许这种歧义的原因之一。是的,我同意,() 一开始看起来很奇怪,但后来你会欣赏额外的清晰度。
  • 考虑到 Barry 的回答,我不会在 QC 中报告此问题。我认为在编译器无法正确确定类型的极少数情况下使用 () 是可以的。
  • Smasher,编译器在错误消息中提到的类型实际上是兼容的。编译器为赋值右侧报告的类型与方法的类型或方法的返回类型不匹配。该问题与任何一种解释是否会产生合法转让无关。

标签: delphi


【解决方案1】:

正如 Mason 所说,Delphi 语法存在歧义。其中TFoo.Bar是一个方法,不清楚FooValue.Bar是指调用TFoo.Bar的结果,还是方法指针(或引用)TFoo.Bar本身(隐含FooValue的Self参数)。

在 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 谢谢!总是很高兴听到以这种方式完成某事的原因。
【解决方案2】:

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

解决它的正确方法是消除句法歧义。在 Dequeue 之后放置一个空括号,以便编译器确定您正在调用该函数,而不是简单地按名称引用它,然后它就会工作。

MyProc := Queue.Dequeue();

【讨论】:

  • 我不确定他想在这里做什么。他是想存储对 Queue.Dequeue 的引用,以便稍后调用 Queue.Dequeue,还是想现在调用 Queue.Dequeue,然后返回结果并将其存储到 myproc 中?
  • 好吧,考虑到queue是TProc的一个队列,而MyProc是TProc类型的变量,应该清楚目的是为了抢返回值。
  • +1 不敢相信这个简单的想法并没有出现在我的脑海中 :) 我不确定你对指针的看法。在我的测试应用程序中,这非常有效。 Pointer (Queue.Dequeue) 似乎是过程的地址,而不是Dequeue 方法的地址。
  • 有趣。刚刚测试了它,它确实有效。不是我所期望的,但还好……
  • Warren,我很清楚他不想将Dequeue 的地址分配给变量,因为它没有正确的类型。该方法的类型是function: TProc of object,而不是procedure of object,所以我有点不明白为什么首先会出现任何错误。 Smasher,要获取方法的地址,您应该使用Addr(),而不是Pointer(),尽管我们通常拼写为@()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-14
  • 2013-08-19
  • 1970-01-01
  • 1970-01-01
  • 2019-05-10
  • 2016-10-27
相关资源
最近更新 更多