IFDEF für generischen Typ

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
MitjaStachowiak
Lazarusforum e. V.
Beiträge: 394
Registriert: Sa 15. Mai 2010, 13:46
CPU-Target: 64 bit
Kontaktdaten:

IFDEF für generischen Typ

Beitrag von MitjaStachowiak »

Hallo,
kann man in Abhängigkeit des Variablentyps, mit dem eine generische Klasse spezialisiert wird, spezifische codes erstellen?

Habe aktuell eine Basisklasse für Funktionen aller Art und die Funktionswerte können entweder einfache Zahlen sein, Arrays mit fixer Größe für Mehrdimensionalität oder auch Arrays mit dynamischer Größe, falls die Anzahl der Dimensionen variieren kann.

Um zum Beispiel die Anzahl der Dimensionen abzufragen verwende ich aktuell folgenden Code:

Code: Alles auswählen

 
type
 MD1d = Precision;
 MD2d = array [0..1] of Precision;
 MD3d = array [0..2] of Precision;
 MDnd = packed object
  private
   function readA(i: cardinal): Precision; inline;
   procedure writeA(i: cardinal; AValue: Precision); inline;
  public
   a : array of Precision;
   property a_ [i:cardinal] : Precision read readA write writeA; default;
  strict private
   {%H-}placeholder : byte; // this is to ensure, that sizeOf(MDnd) is not equal to any of the static array types!
 end;
 PMDnd = ^MDnd;         
 
class function Multidimensional.dim(const a: Preimage): cardinal; inline;
begin
  if (SizeOf(a) = SizeOf(MDnd)) then {%H-}result := length(PMDnd(@a)^.a)
  else {%H-}result := SizeOf(a) div sizeof(Precision);
end;

MDnd ist hier das dynamische Array - naja fast. Damit das Ganze funktioniert, muss ich das dynamische Array zusammen mit einem Platzhalter-Byte in ein packed object schmeißen. Da alle floatingpoint-Typen mehr als ein Byte groß sind, kommt es so zu keinen Überschneidungen in der Variablengröße und ich kann mit sizeOf zwischen den Arraytypen unterscheiden. Beim compilieren gibt es "unreachable code" Warnungen. FPC erkennt also durchaus zur Kompilezeit, was sizeOf liefern wird und kann je nach Spezialisierung des Generics einen Zweig der If-Bedingung wegwerfen 8)

Aber cooler wäre natürlich, man könnte etwas in der Art

Code: Alles auswählen

{$IF a is TArrayType} [...] {$ELSE} [...] {$ENDIF}

verwenden. Aber ich fürchte, diese Kompilerweichen werden vom Preprozessor ausgewerted und sind zum dem Zeitpunkt, zu dem FPC die Generics spezialisiert, schon entfernt. Das heißt, so ein feature zu implementieren wäre relativ aufwändig.

Liege ich mit dieser Einschätzung richtig, oder kann ich hoffen, in naher Zukunft auf das Workaround mit sizeOf verzichten zu können?

By the way: Weil die Generics noch so neu sind, gibt es Codes, die FPC zwar korrekt kompiliert, die der Quelltexteditor in Lazarus aber als ungültig einstuft. Dann geht keine Codevervollständigung mehr. Auch nicht in units, die auf soetwas aufbauen.
Beispiel:

Code: Alles auswählen

generic TGen2<G> = class(specialize TGen1<G>.TSomeSubclass)

führt zu Problemen bei der Codevervollständigung. Ich habe mal folgendes versucht:

Code: Alles auswählen

 
const nix = 1/{$IFDEF NIX}1{$ENDIF}/1 {$DEFINE NOCOMPILE}
;
[...]
generic TGen2<G> = class(specialize TGen1<G>{$IFNDEF NOCOMPILE}.TSomeSubclass{$ENDIF})
 

Viel Spaß beim Nachvollziehen :mrgreen: Jedenfalls wollte ich den Quelltexteditor dazu bringen, teile des Codes auszugrauen, die dann beim compilieren wieder drinn' sind. Geht aber nicht.

MitjaStachowiak
Lazarusforum e. V.
Beiträge: 394
Registriert: Sa 15. Mai 2010, 13:46
CPU-Target: 64 bit
Kontaktdaten:

Re: IFDEF für generischen Typ

Beitrag von MitjaStachowiak »

Ah, hier habe ich was gefunden: http://wiki.freepascal.org/Generics_pro ... k_like_.3F

Sieht wohl so aus, als sei das geplant. Werde dort mal die Idee mit den Ifdefs ergänzen, da die dortigen Vorschläge nicht alle Fälle abdecken.
Zum Beispiel brauche ich passend zu jedem Array aus Float-Werten, wie es im Generic gegeben ist, ein entsprechendes Array aus Integern. Also wenn der generische Typ ein statisches Array ist, will ich auch ein statisches Array aus Integern in der Klasse dazu definieren. Wenn der typ dynamisch ist, muss das Integerarray auch dynamisch sein. Geht aktuellm alles mit sizeOf :|

Antworten