am2
am2

Reputation: 371

Lazarus: typecast overload for generics

I try to build a generic class (f.e. a Set- Class). This class should have a function "AsString". But in it i need to typecast to string. How to declare this typecast?

Short Code:

  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; 

I need a way to typecast FList[i] to string for every "known" special type (of course: each type needs its own operator overloading). something like

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;

Any Idea?

Upvotes: 0

Views: 445

Answers (1)

am2
am2

Reputation: 371

Thanks to David Heffernan and Abelisto. Maybe I did not explain the problem as good as possible, but I got the answers I needed. You see the code of an generic Set- class with 3 specializations: integer, double, TestRecord. I shortened it as much as I could.

It works fine (combination operator overloading and generics). Hope, it helps anyone more than only me.

unit 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.

This is not perfect at all, it only shall show the answer to the question: How can I operator overloading if I want develop generic classes. Any hints to improvement are very welcome.

Upvotes: 2

Related Questions