为什么TFunc<T>可以正确地解引用,但是数组[0..1] of TFunc<T>却不能?

3

如果我有一个TFunc<T: class>类型的变量,则可以直接解引用类成员。
即使是类完成也支持它。

enter image description here

然而,如果我有一个TFunc<T>数组,则无法编译。
为什么?这是编译器错误还是有一些根本原因?

program Project33;
{$APPTYPE CONSOLE}
uses
  System.SysUtils;

type
  TTestObject = class(TInterfacedObject, IInterface)
    procedure Test;
  end;

procedure TTestObject.Test;
begin
  WriteLn('Test');
end;

procedure Test;
var
  A: IInterface;
  TestObject: array [0..4] of TFunc<TTestObject>;
  SingleObject: TFunc<TTestObject>;
  i: integer;
begin
  for i:= 0 to 4 do begin
    a:= TTestObject.Create;
    TestObject[i]:= function: TTestObject
    begin
      Result:= a as TTestObject;
    end;
    TestObject[i].Test;   //<<-- does not compile
    SingleObject:= TestObject[i];
    SingleObject.Test;   // <<-- works.
  end;
end;

begin
  Test; ReadLn;
end.

1
TestObjecti.Test - David Heffernan
@DavidHeffernan 谢谢,太棒了。 - Johan
1
这一定是解析器的怪癖。但基本问题在于语言允许省略函数调用括号,导致歧义。当尝试解决这种歧义时,解析器似乎会感到困惑。 - David Heffernan
非常类似于:https://dev59.com/gV8e5IYBdhLWcg3wEG7A 不确定是否重复...如果不是,@DavidHeffernan,你的评论可能应该成为一个答案。 - J...
@J... 这与调用没有参数的函数时省略括号的棘手问题有关。我写了一个答案,其中包含一些证据表明这是编译器开发人员的疏忽。 - David Heffernan
1个回答

5
Pascal允许在调用没有参数的函数或过程时省略括号。在您的代码中,SingleObject是一个函数。
SingleObject.Test

等同于

SingleObject().Test

这里存在一些歧义。当解析器遇到SingleObject时,它必须决定您是想引用该函数还是调用它。解析器通过考虑上下文来解决这种歧义。在上面的示例中,它决定由于您使用了.运算符,所以您一定是想调用该函数,然后将.运算符应用于从该函数调用返回的值。
现在,对于您的数组示例,解析器似乎遇到了一些歧义。个人认为这是一个疏忽。据我所见,完全可以消除歧义。
考虑以下程序:
type
  TRec = class
    procedure Foo; virtual; abstract;
  end;

  TFunc = function: TRec;
  TFuncOfObj = function: TRec of object;
  TRefFunc = reference to function: TRec;

var
  ScalarFunc: TFunc;
  ArrFunc: array [0..0] of TFunc;
  ScalarFuncOfObj: TFuncOfObj;
  ArrFuncOfObj: array [0..0] of TFuncOfObj;
  ScalarRefFunc: TRefFunc;
  ArrRefFunc: array [0..0] of TRefFunc;

begin
  ScalarFunc.Foo; // fine
  ArrFunc[0].Foo; // fine
  ScalarFuncOfObj.Foo; // fine
  ArrFuncOfObj[0].Foo; // fine
  ScalarRefFunc.Foo; // fine
  ArrRefFunc[0].Foo; // E2003 Undeclared identifier: 'Foo'
end.

正如您所看到的,只有参考函数数组遇到了问题。我怀疑编译器开发人员在添加对参考函数类型支持时,错过了处理这种歧义所需的步骤。

解决方法很容易。您需要明确消除歧义:

ArrRefFunc[0]().Foo;

这个问题的根源是 Pascal 语言决定在函数没有参数时可以省略函数调用的圆括号。在我看来,考虑到现代编程风格中可能出现的歧义问题,回到过去修改这个决定会是一个不错的选择。


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