【问题标题】:Lazarus: typecast overload for genericsLazarus:泛型的类型转换重载
【发布时间】:2017-05-31 13:06:35
【问题描述】:

我尝试构建一个通用类(例如 Set-Class)。这个类应该有一个函数“AsString”。但在其中我需要类型转换为字符串。 如何声明这种类型转换?

短代码:

  generic TSet<_T> = class
  private
    FList: array of _T;
  public
    function AsString:string;
  end;

  TSetDouble = specialize TSet<double>;  

function TSet.AsString: string;
var i:integer;
begin
  result := '';
  for i := 0 to Length(FList) - 1 do
    result := result + IntToStr(i) + ' ' + string (FList[i]) + #13#10;
end; 

我需要一种方法将 FList[i] 类型转换为每个“已知”特殊类型的字符串(当然:每种类型都需要自己的运算符重载)。 像

operator string(const X:integer):string;
begin result := IntToStr(x);end;

operator string(const X:TMyRecord):string;
begin result := IntToStr(MyRecord.Number) + MyRecord.Text;end;

有什么想法吗?

【问题讨论】:

  • 我删除了运算符重载标签。问题不在于运算符重载。这是关于泛型的。它们不是一回事。
  • 没有。重载适用于您定义的有限数量的特定类型。您的代码是通用的,需要适用于任何类型。重载你将一事无成。你要求一个通用的解决方案。我在第一条评论中提出了这一点。我认为您根本不了解通用的含义。在您完全掌握之前,我们将绕着圈子转圈圈。
  • @Abelisto 对泛型没有帮助
  • @Abelisto 好的,所以您同意运算符重载无助于解决问题中提出的问题
  • @Abelisto 问题是关于泛型的。所以任意类型都需要它,否则它不会编译。可能最好的玩具是一些基于 RTTI 的类型嗅探,但重载无济于事。而且我认为 fpc 无论如何都没有强大的 RTTI,所以这是行不通的。

标签: operator-overloading lazarus freepascal


【解决方案1】:

感谢 David Heffernan 和 Abelisto。 也许我没有尽可能好地解释这个问题,但我得到了我需要的答案。您会看到具有 3 个特化的通用 Set 类的代码:整数、双精度、TestRecord。我尽可能地缩短它。

它工作正常(组合运算符重载和泛型)。 希望,它对任何人都有帮助,而不仅仅是我。

单位uSet;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils;

type

  TTestRecord = record
    i:integer;
    t:string;
    x:double;
  end;

  { TSet }

  generic TSet<_T> = class
  private
    FList: array of _T;
    function GetCount: integer;
    function GetItem(const pcnIndex: integer): _T;
    procedure SetItem(const pcnIndex: integer; const pcItem: _T);
  public
    function FindElement(lvI: _T):integer;
    procedure AddItem(lvI: _T);
    procedure DelItem(lvI: _T);
    property Count:integer read GetCount;
    property Item[const pcnIndex:integer]:_T read GetItem write SetItem;default;
    function IsElement(lvI: _T):boolean;
    function AsString:string;
    constructor Create;
    Destructor Destroy;override;
  end;

  TSetString = specialize TSet<string>;
  TSetDouble = specialize TSet<integer>;
  TSetTestRecord = specialize TSet<TTestRecord>;

implementation

//this operator is needed in function FindElement
operator = (const pcR1, pcR2 : TTestRecord) : boolean;begin result := (pcR1.i=pcR2.i) and (pcR1.t=pcR2.t) and (pcR1.x=pcR2.x); end;

//this operator is needed in function AsString
operator explicit (const pcR1 : TTestRecord) : string;begin result := pcR1.t;end;
operator explicit (const X : integer) : string; begin result := inttostr(X);end;
operator explicit (const d : double) : string;begin result := FloatToStr(d) ;end;

{ TSet }

function TSet.GetCount: integer;
begin
  result := length(FList);
end;

function TSet.GetItem(const pcnIndex: integer): _T;
begin
  if (0 <= pcnIndex) and (pcnIndex < length(FList)) then
    result := FList[pcnIndex]
  else
    raise Exception.Create(Format('Index nicht im gültigen Bereich (0<=%d<%d)',[pcnIndex, length(FList)]));
end;

procedure TSet.SetItem(const pcnIndex: integer; const pcItem: _T);
begin
  if (0 <= pcnIndex) and (pcnIndex < length(FList)) then
    FList[pcnIndex] := pcItem
  else
    raise Exception.Create(Format('Index nicht im gültigen Bereich (0<=%d<%d)',[pcnIndex, length(FList)]));
end;

function TSet.FindElement(lvI: _T): integer;
var i:integer;
begin
  result := -1;
  for i := 0 to length(FList) - 1 do
    if lvI = FList[i] then begin
      result := i;
      break;
    end;
end;

procedure TSet.AddItem(lvI: _T);
begin
  if FindElement(lvI) = -1 then begin
    SetLength(FList,length(FList)+1);
    FList[length(FList)-1] := lvI;
  end;
end;

procedure TSet.DelItem(lvI: _T);
var i, lvnIndex:integer;
begin
  lvnIndex := FindElement(lvI);
  if  lvnIndex > -1 then begin
    for i:=lvnIndex to Length(FList)-2 do
      FList[i]:=FList[i+1];
    SetLength(FList,length(FList)-1);
  end;
end;

function TSet.IsElement(lvI: _T): boolean;
begin
  result := FindElement(lvI) > -1;
end;

function TSet.AsString: string;
var i:integer;
begin
  result := '';
  for i := 0 to Length(FList) - 1 do
    result := result + IntToStr(i) + ' ' + string(FList[i]) + #13#10;
end;

constructor TSet.Create;
begin
  inherited Create;
  SetLength(FList,0);
end;

destructor TSet.Destroy;
begin
  SetLength(FList,0);
  inherited Destroy;
end;

end.

这根本不是完美的,它只会显示问题的答案:如果我想开发泛型类,我该如何操作符重载。非常欢迎任何改进提示。

【讨论】:

    猜你喜欢
    • 2012-11-28
    • 1970-01-01
    • 1970-01-01
    • 2017-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多