![]() |
was ist der Sinn von Templates/Generics ?
wenn man schreibt:
Delphi-Quellcode:
kann man doch auch gleich den "Create" Konstrucktor überladen ?
FooResult := TFoo<String>.Create('Hello Free Pascal');
Delphi-Quellcode:
oder seh ich da was falsches ?
type
TFoo = class public Create; overload; Create(String); ... end; |
AW: was ist der Sinn von Templates/Generics ?
Und das machst Du dann für jeden erdenklichen Datentyp inkl. selbstbdeklarierte?
|
AW: was ist der Sinn von Templates/Generics ?
na irgendwie muss man doch dann doch prüfen, welcher Datentyp da dann übergeben wurde ?
im Fall von TFoo<String>.Create in etwa so: IF Type = String THEN ... also ich seh da keinen echten Mehrwert. |
AW: was ist der Sinn von Templates/Generics ?
Wieso musst Du das prüfen? Wenn ich eine TList<TBla> deklariere, dann weiß ich, dass da nur TBla-Elemente enthalten sein können.
|
AW: was ist der Sinn von Templates/Generics ?
Zitat:
Dann hätte das wirklich keinen Mehrwert. |
AW: was ist der Sinn von Templates/Generics ?
also ein Erweiterung von: TList.Objects (die ja nur auf Pointer ausgelegt sind)
obwohl, da könnte man doch auch einen Cast anlegen ? Weil, wofür sollte man Datentypen im Code behandeln, die vorher nicht bekannt sind ? |
AW: was ist der Sinn von Templates/Generics ?
Generics sind dafür gedacht, generischen Code zu schreiben( ja, daher der Name). Das bedeutet, dass man Code entwickelt, der nicht auf einen bestimmten Datentyp festgelegt ist. Zur Compiletime wird der generische Platzhalter dann durch den konkret benutzten Datentyp ersetzt.
|
AW: was ist der Sinn von Templates/Generics ?
Ein kleines Beispiel:
Delphi-Quellcode:
In echtem Code wird das natürlich deutlich umfangreicher. Aber für den Anfang sollte das reichen.
uses
System.Generics.Collections; type TMyValue<T> = class private FValue: T; procedure SetValue(const Value: T); public property Value: T read FValue write SetValue; end; procedure Test; var ValInteger: TMyValue<Integer>; ValList: TMyValue<TList<Integer>>; begin ValInteger := TMyValue<Integer>.Create; try ValInteger.Value := 42; ShowMessage(ValInteger.Value.ToString); finally ValInteger.Free; end; ValList := TMyValue<TList<Integer>>.Create; try ValList.Value := TList<Integer>.Create; ValList.Value.Add(11); ValList.Value.Add(33); ValList.Value.Add(42); ShowMessage(ValList.Value[2].ToString); finally ValList.Free; end; end; procedure TMyValue<T>.SetValue(const Value: T); begin FValue := Value; end; |
AW: was ist der Sinn von Templates/Generics ?
oh Danke.
dachte ich mirs doch: Generics = Vorlagen und Erweiterung von Cast/Pointern, so dass statt einen Pointer, ein konkreter Datentyp bezeichnet/gekennzeichnet wird. macht Sinn... anstelle mit Pointern zu jonglieren, ist dann durch Generics gewährleistet, welcher Typ verwendet wird... ohne das jetzt getestet zu Haben: - können Generics "vererbt" werden (also die Klassen durch Sub-Classing erweitert werden ? |
AW: was ist der Sinn von Templates/Generics ?
Hab ich zwar noch nicht gemacht, aber wieso sollte das nicht gehen? Man muss halt darauf achten, dass die Ableitung auch wieder generisch ist.
|
AW: was ist der Sinn von Templates/Generics ?
Zitat:
Delphi-Quellcode:
, oder wieder nach außen als neuen generischen Typ durchreichen, also
TSubClass = class(TMyValue<Integer>)
Delphi-Quellcode:
. Beides habe ich schon sehr oft verwendet.
TSubClass<T> = class(TMyValue<T>)
|
AW: was ist der Sinn von Templates/Generics ?
Delphi-Quellcode:
Sie Weiteres auch in der OH/DocWiki.
TMyValue = class
function GetValue<T>: T; procedure SetValue<T>(Value: T); end; TMyValue<T> = class function GetValue: T; procedure SetValue(Value: T); end; TMyValue<T> = class procedure Machwas<X>(Value: T; Other: X); end; * mehrere Typen können angegeben werden * es können Einschränkungen Mindestanforderungen für diese Typen vorgegeben werben * uvm. Es kann sogar eine teilweise Automatik (Inferenz) genutzt, wo der Compiler z.B. anhand der übergebenen Variable das T selbst bestimmt.
Delphi-Quellcode:
bei
MyValue.SetValue<Integer>(MyInt);
MyValue.SetValue(MyInt);
Delphi-Quellcode:
aber leider nicht bei
Value: T
Delphi-Quellcode:
Value: array of T
|
AW: was ist der Sinn von Templates/Generics ?
Zitat:
na gut, man kann nicht alles Haben (aber lieber auf der Bank ein Haben haben, als Soll zollen...) |
AW: was ist der Sinn von Templates/Generics ?
Delphi-Quellcode:
bei oben stehenden Code erhalte ich dann die Meldung:
type
QChar<T> = class public type QChar_Category = ( Mark_NonSpacing = 0, Mark_SpacingCombining = 1 ); private FCategory: QChar_Category; public constructor Create; published property Category: QChar_Category read FCategory default Other_NotAssigned; end;
Code:
und beim default Constructor erhalte ich dann:
[dcc64 Fehler] QCharClass.pas(392): E2146 Standardwerte müssen vom Typ Ordinal, Pointer oder vom Typ small Set sein
Code:
constructor QChar.Create;
[dcc64 Fehler] QCharClass.pas(419): E2003 Undeklarierter Bezeichner: 'QChar'
Delphi-Quellcode:
funktioniert dann wieder (als member function).
constructor QChar<T>.Create;
Ich habe das jetzt noch nicht weiter getestet; aber: dann ist ja auch:
Code:
nicht möglich, weil, dann fehlt ja Typ, den man eigentlich mit <T> im Epilog des Klassen-Codes angegeben hat ?
foo := QChar.Create;
|
AW: was ist der Sinn von Templates/Generics ?
Wie gesagt, man kann die Deklaration des Generics an den Typ/Klasse hängen, dann muß es immer angegeben werden, und betrifft die ganze Klasse.
Oder man hängt ihn an die Methode(n), wo es dann jeweils nur diese Methode betrifft und man den Typen selbst auch ohne nutzen kann. Oder man definiert sich eben einen aufgelösten Alias Typen damit.
Delphi-Quellcode:
type
QChar<T> = class ... end; QChar = QChar<string>; Zitat:
|
AW: was ist der Sinn von Templates/Generics ?
Zitat:
|
AW: was ist der Sinn von Templates/Generics ?
ich habe nun folgendes...
Delphi-Quellcode:
ergibt dann:
unit QCharClass;
interface type QChar<T> = class protected function getOrigin: uint64; public constructor Create; overload; ... end; implementation function check_ptr(name: PChar; ptr: uint64): Boolean; begin result := false; if ptr = 0 then begin ErrorMessage(PChar(Format('Error: %s not constructed.',[name]))); exit; end; result := true; end; constructor QChar<T>.Create; begin inherited Create; if not check_ptr(ClassName, getOrigin) then begin Free; exit; end; end; end.
Code:
heißt das nun, ich kann keine Funktionen/Prozeduren im implementation's-Bereich stehen, und nicht direkt mit der QChar<T> zu tun haben, mehr schreiben ?
[dcc64 Fehler] QCharClass.pas(429): E2506 Im interface-Abschnitt deklarierte Methode des parametrisierten Typs darf kein lokales Symbol 'check_ptr' verwenden
|
AW: was ist der Sinn von Templates/Generics ?
Bei einer generischen Klasse kann der Compiler den eigentlichen Code erst erzeugen, wenn der tatsächliche Typ von T bekannt ist. Daher gibt es diese Einschränkung.
Alternativ kannst du die
Delphi-Quellcode:
als Methode der Klasse deklarieren (dann wäre sie ja auch im Interface Part) oder als lokale function innerhalb von
function check_ptr
Delphi-Quellcode:
(wenn sie nicht noch anderswo verwendet wird).
QChar<T>.Create
Abgesehen davon sieht man in deinem Code gar nicht, warum er überhaupt generisch ist. Das T wird nirgendwo verwendet - zumindest nicht in dem Teil den du zeigst. Ich bringe das deswegen auf den Tisch, da es manchmal sinnvoller ist, eine nicht generische Basisklasse zu haben und von der dann ein generische Ableitung zu erstellen, die sich rein um den generischen Part kümmert.
Delphi-Quellcode:
Übrigens: das Free innerhalb des Create ist etwas irritierend.
type
QChar = class protected function getOrigin: uint64; public constructor Create; overload; ... // alles was nicht mit T zu tun hat end; QChar<T> = class(QChar) ... // alles was mit T zu tun hat end; implementation function check_ptr(name: PChar; ptr: uint64): Boolean; begin result := false; if ptr = 0 then begin ErrorMessage(PChar(Format('Error: %s not constructed.',[name]))); exit; end; result := true; end; constructor QChar.Create; begin inherited Create; if not check_ptr(ClassName, getOrigin) then begin Free; exit; end; end; |
AW: was ist der Sinn von Templates/Generics ?
Wozu Free?
Erst garnicht erzeugen, wenn nicht nötig oder möglich.
Delphi-Quellcode:
type
QChar = class private // or protected or public class function check_ptr(name: PChar; ptr: uint64): Boolean; static; protected function getOrigin: uint64; public //constructor Create; //class function Create: QChar; static; // intern nur dann erzeugen, wenn nötig class function CreateOrNot: QChar; static; // da dieses "Create" unerwartet auch NIL zurückgeben kann, sollte das auch ersichtlich sein. end; class function QChar.check_ptr(name: PChar; ptr: uint64): Boolean; begin Result := ptr <> 0; if not Result then ErrorMessage(PChar(Format('Error: %s not constructed.',[name]))); end; class function QChar.CreateOrNot: QChar; begin Result := nil; if check_ptr(ClassName, getOrigin) then Result := inherited Create; end; x := QChar.CreateOrNot; if Assigned(x) then ... |
AW: was ist der Sinn von Templates/Generics ?
Zitat:
Zitat:
Man könnte das auch auslagern. Aber ich dachte mir, da der Code in einer DLL liegt, das auslösen einer Exception nicht so dolle erscheinen mag. das ganze kann auch ![]() |
AW: was ist der Sinn von Templates/Generics ?
Ein Class.Create Constructor gibt per Definition IMMER das Objekt zurück und wenn nicht, dann wird ordnungsgemäß eine Exception geworfen.
|
AW: was ist der Sinn von Templates/Generics ?
Und weshalb werden hier immer wieder unaufgefordert solche Code-Monster gepostet, die doch kein Mensch liest? TL;DR
|
AW: was ist der Sinn von Templates/Generics ?
Zitat:
|
AW: was ist der Sinn von Templates/Generics ?
in dem Zusammenhang mit Templates (jetzt in GNU C++) ...
Code:
in der Funktion oben caste ich einen bereits erstellten Klassen-Pointer (vieleicht nicht die beste Lösung, aber das sei erstmal dahingestellt).
class TObject {
public: virtual std::string ClassName() const; virtual ~TObject(); }; template <typename T> class QChar: public TObject { public: // constructor QChar(T); }; extern "C" { DLL_EXPORT bool isBlank_QChar(uint64_t addr) { auto * objptr = reinterpret_cast<qvc::QChar*>(addr); check_pointer(addr, reinterpret_cast<uint64_t>(objptr)); std::cout << "objptr = " << objptr->ClassName() << std::endl; if (objptr->isBlank()) return true; return false; } }; Die Frage ist aber nun: wie kann ich in der Zeile:
Code:
den Typen erhalten ?
auto * objptr = reinterpret_cast<qvc::QChar*>(addr);
muss ich dazu den Typen während der Initialization speichern, um ihn dann and <qvc::QChar*> angeben zu können ? wie macht man das ? |
AW: was ist der Sinn von Templates/Generics ?
Free im Constructor ist nicht zulässig, da dann ein Zeiger auf die nicht mehr existierende Objectinstance zurückgegeben wird.
Die einzige Möglichkeit den Constructor abzubrechen ist eine Exception. Ich habe noch nicht verstanden was du eigentlich erreichen willst. Vieleicht erklärst du das ausführlicher. Wahrscheinlich ist das sogar ein neues Thema. Leitet man von einem Generic eine konkrete Klasse ab, bestimmt man damit Classname selbst. Ist ein Object erstellt, kann man auf Object.ClassName und Object.ClassType zugreifen. Erstellt man ein Object direkt von einem Generic, leitet Delphi selbständig eine konkrete Klasse ab. |
AW: was ist der Sinn von Templates/Generics ?
ich habe das ganze schon fast gelöst, das Projekt kann in meinen letzten Link betrachtet werden.
Das Projekt, an dem ich gerade sitze ist folgendes: - FPC mit GNU C++ zu kombinieren, so dass dann: - die FPC VCL (die der Delphi VCL entspricht) mit den GNU C++ zu verknüpfen. so hat man dann einheitliche Funktionen, die sowohl in FPC und GNU C++ verwendet werden können. Erst wollte ich das Qt-Framework, das unter GNU C++ geschrieben wurde in FPC zugänglich machen. Aber da gibt es schon anstrengungen, die mir aber nicht gefallen, da diese vorwiegend prozedural gehalten sind - mein Ansatz aber das Klassen-Model nutzen soll, so dass man dann nicht mehr: ptr := Create_QWidget(); hat, sondern: ptr := QWidget.Create; was für mich eindeutig komfortabler ist. Da ich nun verschiedene Datentypen unterstützen würde, habe ich erstmal normale klassische OOP angewendet. Jetzt aber auf den aufsteigenden Ast bin, auch in die tiefen der Template-Verarbeitung zu steigen. Ob das dann zweckmäßig erscheint, sei erstmal dahin gestellt - zumal es für mich auch eine Art Übung und Lehrzweck dient. Also seid da nicht emboßt, wenn der Quellcode wie Kraut und Rüben ausschaut - bin halt kein richtiger Programmierer - also angelernt... |
AW: was ist der Sinn von Templates/Generics ?
in Delphi kann man Methoden einer Klasse auch als EXTERNAL deklarieren
und dann als Einzelfunktionen z.B. in einer DLL (Delphi, C+++ oder sonstwas) exporieren, welche von der Delphi-Klasse dann genutzt werden. Ansonsten einfach einen Record, darin Pointer-Variablen auf Funktionen. (ähnlich dem TMemoryManager in der System-Unit, was auch zwischen Delphi und C++Builder genutzt werden kann) |
AW: was ist der Sinn von Templates/Generics ?
Zitat:
aber ich habe jetzt festgestellt, das ich ALLE ctor's wegschneiden kann, und durch ein Template ersetzen kann. Das spart in meiner momentanen Sicht der Weise, an binären Speicherplatz. Klar, man hat vielleicht einen kleinen Payload - aber der ist, so denke ich, schnell wieder reingeholt. |
AW: was ist der Sinn von Templates/Generics ?
Zitat:
Delphi-Quellcode:
irgendwie finde ich das Klasse, was man so machen kann - zumal man auch Code sparrt ...
constructor QChar<T>.Create(v: Array of T);
var i: Integer; begin for i := 0 to High(v) do foo := v[i]; end; |
AW: was ist der Sinn von Templates/Generics ?
Zitat:
|
AW: was ist der Sinn von Templates/Generics ?
okay folgendes funktioniert dann auch nicht:
Delphi-Quellcode:
hier bekomme ich dann die Meldung "inkompatible Typen". urgg..
procedure foo;
var myQChar: QChar<Array of Char>; begin myQChar := QChar<Array of Char>.Create([' ', ' ']); end; Edit: Solution:
Delphi-Quellcode:
procedure foo;
var myQChar: QChar<TArray<Char>>; begin myQChar := QChar<TArray<Char>>.Create([' ', ' ']); end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:13 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz