模板(或其他技术)是否支持以下构造?

发布于 2024-09-28 14:55:56 字数 829 浏览 14 评论 0原文

这是我的 其他问题的后续内容

当我第一次听说泛型时,是在 Delphi 2009 发布之前(他们首先在其中引入它)。我知道 .Net 之前就支持它,但我还没有深入研究这个领域。

阅读有关泛型的内容后,我了解到它允许类具有变量参数,并且您传递给它的任何值都将被该类的所有代码替换。

描述泛型的方式(或者至少是我所理解的泛型允许的方式)是,给出以下声明:

procedure TMyClass<T>.Init;
begin
  FField := T.Create(nil);
end;

我认为它会起作用。我假设编译失败的地方如下:

begin
  TMyClass<TComponent>.Create; //Works correctly
  TMyClass<TObject>.Create;  //Doesn't work, as even though it HAS a constructor, it has none that receive a single pointer parameter
  TMyClass<string>.Create; //Doesn't work, not an object. 
end;

现在,我很清楚我错了。所以,我现在想知道是否有一种技术/语言功能可以支持这种构造。也许是代码模板?其他编程语言中的泛型?或者也许是别的什么?

This is kind of a follow-up from my other question.

When I first heard about generics, it was before the release of Delphi 2009 (Where they introduced it first). I know it was supported in .Net before that, but I have yet to dig in that realm.

Reading about generics, I learned that it allowed class to have a variable argument to it, and that whatever value you passed to it would then be replaced through all the code of the class.

The way generics were described (or at least, what I understood generics allowed) was that, given the following declaration:

procedure TMyClass<T>.Init;
begin
  FField := T.Create(nil);
end;

I assumed it would work. I assumed where the compile would fail is as follow:

begin
  TMyClass<TComponent>.Create; //Works correctly
  TMyClass<TObject>.Create;  //Doesn't work, as even though it HAS a constructor, it has none that receive a single pointer parameter
  TMyClass<string>.Create; //Doesn't work, not an object. 
end;

Now, I well know I was wrong. So, what I wonder now, is there a technology/language feature that would support such a construct. Code templates perhaps? Generics in other programming languages? Or maybe something else?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

伴我心暖 2024-10-05 14:55:56

现在,我清楚地知道我错了。所以呢
我现在想知道,有没有一个
技术/语言功能
支持这样的构造。代码
也许是模板?其他中的泛型
编程语言?或者也许
还有别的吗?

C# 中的泛型具有您想要的功能。 C++ 中的模板甚至更强大 - 通过模板生成的代码与手工编写的代码相同,除了只能内联编译的部分,这很糟糕。

Now, I well know I was wrong. So, what
I wonder now, is there a
technology/language feature that would
support such a construct. Code
templates perhaps? Generics in other
programming languages? Or maybe
something else?

Generics in C# have the power that you want. Templates in C++ are even stronger - code generated via template is identical to code written by hand, except for the part where they can only be compiled inline, which sucks.

落在眉间の轻吻 2024-10-05 14:55:56

@Gamecat,您不能将 TObject 作为约束,但可以将 class 作为约束(这很好地弥补了 TObject 约束的缺乏) 。

请注意,无论您使用 TObject 还是 class,如果没有技巧,您都无法使用参数调用 Create

示例 1:class 约束:

unit Unit1;

interface

uses
  Classes;

type
  TMyClass<T: class, constructor> = class
  strict private
    FField: T;
  public
    procedure Init;
  end;

implementation

procedure TMyClass<T>.Init;
begin
  FField := T.Create();
end;

end.

示例 2:TComponent 作为约束,并且在 Create

unit Unit2;

interface

uses
  Classes;

type
  TMyClass<T: TComponent, constructor> = class
  strict private
    FField: T;
  public
    procedure Init;
  end;

implementation

procedure TMyClass<T>.Init;
var
  ComponentClass: TComponentClass;
begin
  ComponentClass := T;
  FField := ComponentClass.Create(nil);
end;

end.

除了 class 之外的 参数code>约束,也可以有记录约束。
这样,您需要使用 Default 来初始化字段:

unit Unit3;

interface

uses
  Classes;

type
  TMyClass<T: record> = class
  strict private
    FField: T;
  public
    procedure Init;
  end;

implementation

procedure TMyClass<T>.Init;
begin
  FField := Default(T);
end;

end.

希望这能让您对泛型和约束有所了解。

——杰罗恩

@Gamecat, you cannot have TObject as a constraint, but you can have class as a constraint (which nicelly covers that lack of TObject constraint).

Note that no matter if you use TObject or class, you cannot call the Create with a parameter without a trick.

Example 1: class constraint:

unit Unit1;

interface

uses
  Classes;

type
  TMyClass<T: class, constructor> = class
  strict private
    FField: T;
  public
    procedure Init;
  end;

implementation

procedure TMyClass<T>.Init;
begin
  FField := T.Create();
end;

end.

Example 2: TComponent as a constraint, and parameter in the Create

unit Unit2;

interface

uses
  Classes;

type
  TMyClass<T: TComponent, constructor> = class
  strict private
    FField: T;
  public
    procedure Init;
  end;

implementation

procedure TMyClass<T>.Init;
var
  ComponentClass: TComponentClass;
begin
  ComponentClass := T;
  FField := ComponentClass.Create(nil);
end;

end.

In addition to the class constraint, you can also have a record constraint.
With that, you need the Default to initialize fields:

unit Unit3;

interface

uses
  Classes;

type
  TMyClass<T: record> = class
  strict private
    FField: T;
  public
    procedure Init;
  end;

implementation

procedure TMyClass<T>.Init;
begin
  FField := Default(T);
end;

end.

Hope that sheds some light on generics and constraints.

--jeroen

心安伴我暖 2024-10-05 14:55:56

您可以对泛型类型施加约束。如果您想使用该类型的某些方面,则需要它。比如一个方法。

如果要调用构造函数,则需要在类约束旁边给出构造函数约束:

type
  TMyClass<T: TComponent, constructor> = class
    // ..
  end;

procedure TMyClass<T>.Init;
begin
  FField := T.Create(nil);
end;

不幸的是,TObject 不是有效的约束。 (根据德尔福 XE)。

现在,我清楚地知道我错了。所以,我现在想知道,是否有一种技术/语言特性可以支持这种构造。也许是代码模板?其他编程语言中的泛型?或者也许是别的什么?
这可能是有风险的,甚至是毫无意义的。如果您在泛型上调用方法 X,并使用不支持方法 X 的类实例化它,那么正确的行为是什么...

You can put constraint(s) on a generic type. You need this if you want to use certain aspects of that type. For example a method.

If you want to call a constructor, you need to give the consructor constraint next to the class constraint:

type
  TMyClass<T: TComponent, constructor> = class
    // ..
  end;

procedure TMyClass<T>.Init;
begin
  FField := T.Create(nil);
end;

Unfortunately TObject isn't a valid constraint. (according to Delphi XE).

Now, I well know I was wrong. So, what I wonder now, is there a technology/language >feature that would support such a construct. Code templates perhaps? Generics in other >programming languages? Or maybe something else?
This can be risky or even meaningless. If you call method X on the generic and you instantiate it with a class that doesn't support method X, what is the correct behaviour...

落在眉间の轻吻 2024-10-05 14:55:56

@Ken:为了让像您所请求的代码以真正的通用方式工作,您需要有一个统一的类型系统来合并引用类型(类)和值类型(字符串、整数等)。

从历史上看,本机 Delphi 没有这样的类型系统(.NET 有,并且 Delphi Prism 中的泛型支持它,就像 C# 和 VB.NET 一样)。

解决这个问题很困难; Allen Bauer 尝试过实现 Nullable 类型,他必须进行一些认真的调整,以涵盖引用类型和值类型的方式仅实现 Equals (=) 和 NotEquals (<>) 运算符行为。

因此,支持这些将是困难的,但可能是可行的:

begin
  TMyClass<TComponent>.Create; //Works correctly
  TMyClass<TObject>.Create;  //Doesn't work, as even though it HAS a constructor, it has none that receive a single pointer parameter
  TMyClass<string>.Create; //Doesn't work, not an object.
end;

--jeroen

@Ken: In order for code like you requested to work in a real generic way, you would need to have a unified typing tystem that merges both reference types (classes) and value types (strings, integers, etc).

Historically, native Delphi doesn't have such a typing system (.NET has, and generics in Delphi Prism supports it, just as C# and VB.NET do).

Working around that is difficult; Allen Bauer gave it a shot implementing a Nullable type, and he had to do some serious twisting to implement only the Equals (=) and NotEquals (<>) operator behaviour in a way that covers both reference and value types.

So supporting these will be tough, but probably doable:

begin
  TMyClass<TComponent>.Create; //Works correctly
  TMyClass<TObject>.Create;  //Doesn't work, as even though it HAS a constructor, it has none that receive a single pointer parameter
  TMyClass<string>.Create; //Doesn't work, not an object.
end;

--jeroen

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文