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

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
