Enumerator von generischer Klasse?

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
Joz
Beiträge: 40
Registriert: Mo 27. Mai 2013, 13:16
OS, Lazarus, FPC: Arch Linux, OpenSuse 13.2, Lazarus 1.4
CPU-Target: AMD64
Wohnort: Berlin

Enumerator von generischer Klasse?

Beitrag von Joz »

Hallo alle zusammen!
Ich habe eine generische Klasse TSmartArray, die ich in einer for-in-loop ansprechen können möchte. Wie definiere ich einen Enumerator dafür?
Mein Problem ist, dass man eine Im-Voraus-Deklaration benutzen muss, die bei Generischen Typen nicht geht oder anders aussieht. Das Beispiel in der Freepascal-Wiki sieht so aus:

Code: Alles auswählen

TEnumerableTree = class;     // Vor-Deklaration
 
TTreeEnumerator = class
…
  constructor Create(ATree: TEnumerableTree);
Diese Art der Deklaration funktioniert aber für generics nicht. Jede Zeile des folgenden Codes, die die jeweils andere Klasse spezialisieren will, wirft die Fehlermeldung „Specialization is only supported for generic types.“
Ich schließe daraus, dass die Voraus-Deklaration nicht geklappt hat.

Code: Alles auswählen

unit SmartArray;
 
{$mode objfpc}{$H+}
 
interface
 
type
  generic TSmartArray<T> = class;
 
  generic TSmartArrayEnum<T> = class
    type
      TContainer = specialize TSmartArray<T>;    //  Error: Specialization is only supported for generic types
    private
      FIndex: SizeInt;
      function GetCurrent: T;
    public
      constructor Create(ASmartArray: TContainer);
      function MoveNext: Boolean;
      property Current: T read GetCurrent;
  end;
 
  generic TSmartArray<T> = class
    type
      TEnum = specialize TSmartArrayEnum<T>;
    private
      …
    public
      constructor Create;
      procedure Add(N: T);
      function GetEnumerator: specialize TSmartArrayEnum<T>;
      procedure Clear;
      destructor Destroy;
      property Length: SizeInt read FCount;
      property Elements[Index: SizeInt]: T read GetElement write SetElement; default;
      property Low: SizeInt read FLow write SetLow;
      property High: SizeInt read GetHigh;
      property MemSize: SizeInt read GetBufSize write SetMemSize;
  end;
 
 
implementation
Kennt jemand einen Ausweg für mich? Oder muss ich bei Generics auf For-in-Loops verzichten?

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Enumerator von generischer Klasse?

Beitrag von Socke »

Schau mal in der Unit fgl nach. Dort sind verschiedene generische Listen (z.B. TFPGList) defniert; die Enumerator-Klassen sind innerhalb dieser Klasse definiert.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Joz
Beiträge: 40
Registriert: Mo 27. Mai 2013, 13:16
OS, Lazarus, FPC: Arch Linux, OpenSuse 13.2, Lazarus 1.4
CPU-Target: AMD64
Wohnort: Berlin

Re: Enumerator von generischer Klasse?

Beitrag von Joz »

Dankeschön, die Unit beschreibt einen schönen Weg, um das hinzubekommen, hab es dadurch lösen können!

Der ungefähre Code sieht jetzt so aus:

Code: Alles auswählen

TAbstractSmartArray = class
  public
    { Gibt einen Zeiger auf Element I zurück, falls vorhanden, sonst nil }
    function GetElemPtr(I: SizeInt): Pointer; virtual; abstract;
    function GetLow: SizeInt; virtual; abstract;
  end;
 
  generic TSmartEnum<T> = class
    type PT = ^T;
    private
      FSource: TAbstractSmartArray;
      FCurr: PT;
      FIndex: SizeInt;
      function GetCurrent: T;
      procedure SetCurrent(ACurrent: T);
    public
      constructor Create(ASource: TAbstractSmartArray);
      function MoveNext: Boolean;
      property Current: T read GetCurrent write SetCurrent;
  end;
 
  generic TSmartArray<T> = class(TAbstractSmartArray)
  type
      TTArray = array of T;
      TEnum = specialize TSmartEnum<T>;
  …
    function GetEnumerator: TEnum;
  end;

Antworten