Jea*_*ond 5 delphi generics math templates addition
我是Delphi的新手.对于我公司要求的项目,我需要将现有C++类中的一些代码翻译成Delphi.其中一些类是模板,例如:
template <class T>
struct APoint
{
T m_X;
T m_Y;
virtual void Add(T value);
};
template <class T>
void APoint<T>::Add(T value)
{
m_X += value;
m_Y += value;
}
Run Code Online (Sandbox Code Playgroud)
我使用它,例如使用此代码
APoint<float> pt;
pt.m_X = 2.0f;
pt.m_Y = 4.0f;
pt.Add(5.0f);
Run Code Online (Sandbox Code Playgroud)
这很有效.
现在我需要为Delphi编写等效的代码.我试着写一个Delphi Generic类,基于上面的C++代码:
APoint<T> = record
m_X: T;
m_Y: T;
procedure Add(value: T);
end;
procedure APoint<T>.Add(value: T);
begin
m_X := m_X + value;
m_Y := m_Y + value;
end;
Run Code Online (Sandbox Code Playgroud)
但是这段代码无法编译.我收到此错误:
E2015运算符不适用于此操作数类型
AFAIK这个代码应该可行,我不明白它有什么问题.那么任何人都可以向我解释:
为什么这样的代码不能在Delphi中编译?
Delphi中创建一个提供Add()函数的模板类的正确(和最简单)方法是什么,尽可能接近上面的C++代码和用法?
2016年10月17日编辑
感谢所有的答复.因此,如果我理解正确,就无法创建类似c ++的样式模板,因为Delphi强加了c ++中不存在的几个约束.
基于此,我搜索了一个解决方法,以达到我想要的目标.我找到了以下解决方案:
IPoint<T> = interface
procedure Add(value: T);
end;
APoint<T> = class(TInterfacedObject, IPoint<T>)
m_X: T;
m_Y: T;
procedure Add(value: T); virtual; abstract;
end;
APointF = class(APoint<Single>)
destructor Destroy; override;
procedure Add(value: Single); reintroduce;
end;
destructor APointF.Destroy;
begin
inherited Destroy;
end;
procedure APointF.Add(value: Single);
begin
m_X := m_X + value;
m_Y := m_Y + value;
end;
Run Code Online (Sandbox Code Playgroud)
我使用它,例如使用此代码
procedure AddPoint;
var
pt: IPoint<Single>;
begin
pt := APointF.Create;
APointF(pt).m_X := 2.0;
APointF(pt).m_Y := 4.0;
APointF(pt).Add(5.0);
end;
Run Code Online (Sandbox Code Playgroud)
这很有效.但是我发现风格有点重,例如使用APointF(pt)的必要性.所以,就上面的代码而言,我的问题是:
最后,我在Delphi代码中看到了另一种解决方案,可以通过这种方式实现2种泛型类型的相等比较:
function APoint<T>.IsEqual(const other: APoint<T>): Boolean;
var
comparer: IEqualityComparer<T>;
begin
Result := (comparer.Equals(m_X, other.m_X) and comparer.Equals(m_Y, other.m_Y));
end;
Run Code Online (Sandbox Code Playgroud)
我试着阅读幕后的代码,但是我发现它非常复杂.所以,我的问题是:
提前感谢您的回复
问候
Delphi Generics与C++模板本质上不同,它们更像C#对应物.
在C++中,您可以对模板类型执行任何操作,并且在模板实例化时,编译器会检查您在模板中执行的操作是否适用于您正在使用的特定类型.如果没有,您会收到编译器错误.
在Delphi(和许多其他语言)中,您声明一个泛型类型可能提供一些声明性约束,而这些约束 - 基类或接口 - 确定您可以对泛型类型执行的操作.在实例化时,唯一的检查是声明的类型是否适合约束.
可以说,Delphi语言可以为浮点或序数类型添加约束,但这会提供非常有限的灵活性(更改可在通用实例中使用的浮点或整数类型).我个人并不认为这是一个关键特征.
Delphi泛型不支持对泛型类型起作用的算术运算符。为了使编译器接受代码,它需要知道对通用类型的每个操作在实例化时将可用。
通用约束使您可以告诉编译器类型具有哪些功能。但是,通用约束不允许您告诉编译器该类型支持arithmetjc运算符。
不幸的是,您试图做的事根本不可能。当然,您可以自己构建框架,这些框架可以使用诸如接口之类的工具来执行算法,但是这样做会降低性能。如果可以接受,那么可以。否则,最好是硬着头皮避免在这里使用泛型。
哦,对于C ++模板。
向其他正在寻找 Object Pascal 解决方案来解决这个普遍问题的人指出这一点:
请注意,Free Pascal 非常简单地支持他们在这里尝试做的事情(即使在“Delphi 语法兼容性”模式下也是如此。)
作为一个长期只使用 Free Pascal 的人,当我意识到情况确实如此时,老实说,我对 Delphi 根本不允许这样做感到非常惊讶。在我看来,这是一个重大限制。
有效的自由帕斯卡代码:
program Example;
// Using Delphi-mode here allows us to declare and use
// generics with the same syntax as Delphi, as opposed to
// needing the "generic" and "specialize" keywords that
// FPC normally requires.
{$mode Delphi}
// To allow +=, another nice FPC feature...
{$COperators On}
type
TGPoint<T> = record
X, Y: T;
// static class function instead of constructor here so we can inline it
class function Create(constref AX, AY: T): TGPoint<T>; static; inline;
// define our operator overload
class operator Add(constref Left, Right: TGPoint<T>): TGPoint<T>; inline;
end;
class function TGPoint<T>.Create(constref AX, AY: T): TGPoint<T>;
begin
with Result do begin
X := AX;
Y := AY;
end;
end;
class operator TGPoint<T>.Add(constref Left, Right: TGPoint<T>): TGPoint<T>;
begin
with Result do begin
X := Left.X + Right.X;
Y := Left.Y + Right.Y;
end;
end;
var SP: TGPoint<String>;
begin
SP := TGPoint<String>.Create('Hello, ', 'Hello, ');
SP += TGPoint<String>.Create('world!', 'world!');
with SP do begin
WriteLn(X);
WriteLn(Y);
end;
end.
Run Code Online (Sandbox Code Playgroud)
程序当然会打印:
Hello, world!
Hello, world!
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
703 次 |
| 最近记录: |