从通用容器中检索TProc

jpf*_*ius 7 delphi

刚发现一些相当有趣的东西

var
  Queue  : TQueue <TProc>;
  MyProc : TProc;
...
MyProc := Queue.Dequeue;
Run Code Online (Sandbox Code Playgroud)

我想你看到这里有什么意思.但是,编译器认为我想存储Queue.Dequeue方法(键入"对象的过程")MyProc并报告错误

E2010 Incompatible Types: 'TProc' und 'Procedure of object'
Run Code Online (Sandbox Code Playgroud)

我想出的解决方法是这样的

MyProc := TProc (Pointer (Queue.Dequeue));
Run Code Online (Sandbox Code Playgroud)

有更优雅的解决方案吗?

Mas*_*ler 11

关于名称"Dequeue"是指函数本身还是函数的返回值,存在一些语法模糊性.而且由于你正在处理一个匿名方法指针,你可以指定一个普通函数,它试图将其解释为函数赋值,而不是函数结果赋值.将它转换为指针是错误的解决方案,因为这会强制执行函数分配,这会在您尝试调用MyProc时导致各种有趣的错误.

解决它的正确方法是消除语法歧义.在Dequeue之后放一个空括号,这样编译器就可以确定你正在调用该函数而不是简单地按名称引用它,然后它就可以工作了.

MyProc := Queue.Dequeue();
Run Code Online (Sandbox Code Playgroud)


Bar*_*lly 6

正如梅森所说,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