3
type
  TForm72 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }    
  end;

  TTestForm = class(TForm)
  public
    constructor CreateTest(AOwner: TComponent); virtual;
  end;

  TTestForm1 = class(TTestForm)    
  public
    constructor CreateTest(AOwner: TComponent); override;
  end;

  TTest<T: TTestForm, constructor> = class(TObject)
  public
    class procedure Test;
  end;

var
  Form72: TForm72;

implementation

{$R *.dfm}

procedure TForm72.FormCreate(Sender: TObject);
begin
  TTest<TTestForm1>.Test;
end;

{ TTest<T> }

class procedure TTest<T>.Test;
var
  F: T;
begin
  F := T.CreateTest(Application);
  Form72.Caption :=  F.Name;
end;

{ TTestForm }

constructor TTestForm.CreateTest(AOwner: TComponent);
begin
  inherited Create(AOwner);
end;

{ TTestForm1 }

constructor TTestForm1.CreateTest(AOwner: TComponent);
begin
  inherited;
  Caption := 'Bang';
end;

end.

此代码在 XE2 中编译,但在 XE3 中出现“[dcc32 Error] Unit71.pas(55): E2010 Incompatible types: 'T' and 'procedure, untyped pointer or untyped parameter'”失败。我做错了什么,或者编译器做错了什么?

4

1 回答 1

4

事实上,这段代码突出了 XE2 中的一个编译器错误。在 XE2 中,代码在不应该编译的时候编译。删除constructor约束,编译失败

E2568 无法在类型中没有 CONSTRUCTOR 约束的情况下创建新实例
参数声明

但该constructor约束仅表明该类具有无参数构造函数。该文档指出:

构造函数约束

类型参数可能受保留字“构造函数”的零个或一个实例的约束。这意味着实际的参数类型必须是定义默认构造函数(公共无参数构造函数)的类,以便泛型类型中的方法可以使用参数类型的默认构造函数构造参数类型的实例,而无需了解有关参数的任何信息类型本身(没有最低基本类型要求)。

约束的存在与否constructor影响此代码的事实表明 XE2 编译器存在错误。


在 XE3 中,代码正确无法编译。使用语法调用构造函数的唯一方法T.Create是使用constructor约束并调用无参数构造函数。这不是这里的情况,所以 XE3 正确地报告了一个编译错误。

您需要进行一些转换才能使其编译。

F := T(TTestForm(T).CreateTest(Application));

这是一个众所周知的技巧,可以绕过 Delphi 泛型实现处理构造函数的一些怪癖。虽然看起来很乱,但我相信这段代码是语言设计者打算让我们使用的。在我看来,行为的变化是由于错误修复和 XE3 的行为设计。

于 2012-10-05T15:35:22.910 回答