Angabe oberer Typgrenze bei Templates möglich ?
-
Hallo , wollte mir zur Übung ,da ich grade erst angefangen habe C++ zu lernen mal wieder einen eigenen kleinen binären Baum schreiben.........
Da ich generische Typen bereits aus Java kenne wollte ich natürlich auch hier dafür sorgen , dass Elemente eines beliebigen Typs im Baum abgelegt werden können.....
Daher die Farge , denn es muss ja mindestens sichergestellt sein , dass die übergeben Typen eine Art compareTo() -Funktion oder entsprechende Vergleichoperatoren zur Verfügung stellen um den Baum aufbauen zu können........
Muss ich jetzt wirklich einen festen abstarkten Typ angeben , von dem ich alles zusätzlich ableite das ich übergeben will um den Besitz der Funktionen sicher zu stellen ? Danke im Vorraus für die schnelle Hilfe
-
Erstmal: C++-Templates und Java-Generics haben große Unterschiede. Beides kann man nicht so recht miteinander vergleichen.
Wenn der in deinem Baum abgelegte Typ keinen Vergleichsoperator hat, du diesen aber benutzt, dann wird dir der Compiler schon rechtzeitig ins Gesicht springen - du brauchst also nicht jeden Typ von einem Comparable oder ähnlichem abzuleiten.
-
@Pumuckel:
Also über Java Generices weis ich nur dass sie ohne Änderung der virtuellen Maschine eingeführt wurden , was zur Folge hat das jede generische Klasse im ByteCode auf alten mit Objekt parametrierten Code abgebildet wird.Gibt man einen Typ als Obergrenze wird das Generic damit in alten ByteCode gewandelt und man kann intern Typ-spezifische Eigenschaften eincodieren. Wird das Generic dann irgendwo verwendet werden in den Code an entsprechdner Stelle einfach die entsprechenden Rückcasts eingefügt. Die Abbildung auf alten Code bringt
damit Einschränkung weil zur Laufzeit keine Typinformation in dem Generic vorliegt.Ist das soweit richtig ?So..... Templates nehme ich an werden dann wahrscheinlich bei jeder Verwendung mit einem speziellen Typ für den jeweiligen Typ compiliert ???Was aber noch nicht wirklich meine Frage beantwortet :
Wenn ich in einem Template eine Klassenspezifische Funktion oder Eigenschaft nutzen und hart eincodieren möchte , dann müsste ich doch die Möglichkeit haben wie in Java eine Typobergrenze anzugeben ,die diese sicherstellt ,dass der Compiler bei Typspezifischen hart eincodierten Funtionsaufrufen nicht meckert.In meinem Fall geht es ja um die Vergleichsoperatoren und ich dachte Operatoren sind auch nur Funktionen.Warum also meckert der Compiler nicht wenn
man die Vergleichsoperatoren für irgendwelche noch offenen Typen in ein Template hart eincodiert.Deine Antwort kann ich damit nur nachvollziehen wenn
Vergleichsoperatoren=Funktionen standartmäßig für jede Klasse generiert würden...ist das so??? Und was machen die dann standartmäßig?? Adressvergleich??? Danke für die Hilfe nochmal
-
Toman schrieb:
@Pumuckel:
Also über Java Generices weis ich nur dass sie ohne Änderung der virtuellen Maschine eingeführt wurden , was zur Folge hat das jede generische Klasse im ByteCode auf alten mit Objekt parametrierten Code abgebildet wird.Gibt man einen Typ als Obergrenze wird das Generic damit in alten ByteCode gewandelt und man kann intern Typ-spezifische Eigenschaften eincodieren. Wird das Generic dann irgendwo verwendet werden in den Code an entsprechdner Stelle einfach die entsprechenden Rückcasts eingefügt. Die Abbildung auf alten Code bringt
damit Einschränkung weil zur Laufzeit keine Typinformation in dem Generic vorliegt.Ist das soweit richtig ?So..... Templates nehme ich an werden dann wahrscheinlich bei jeder Verwendung mit einem speziellen Typ für den jeweiligen Typ compiliert ???Ja.
Was aber noch nicht wirklich meine Frage beantwortet :
Wenn ich in einem Template eine Klassenspezifische Funktion oder Eigenschaft nutzen und hart eincodieren möchte , dann müsste ich doch die Möglichkeit haben wie in Java eine Typobergrenze anzugeben ,die diese sicherstellt ,dass der Compiler bei Typspezifischen hart eincodierten Funtionsaufrufen nicht meckert.In meinem Fall geht es ja um die Vergleichsoperatoren und ich dachte Operatoren sind auch nur Funktionen.Warum also meckert der Compiler nicht wenn
man die Vergleichsoperatoren für irgendwelche noch offenen Typen in ein Template hart eincodiert.Weil der Compiler das Template mit dem Typ X erst dann compiliert wenn du angibst dass du es mit Typ X benutzen willst. Soll heißten wenn du nie
myTemplate<X>schreibst, wird der Compiler auch nie versuchen, die darin vorhandenen Vergleiche auf ein X anzuwenden.Deine Antwort kann ich damit nur nachvollziehen wenn
Vergleichsoperatoren=Funktionen standartmäßig für jede Klasse generiert würden...ist das so???Nein, genau andersrum. Ganz im Gegensatz zu den Java Generics, die einmalig und sofort für alle Typen die rein können sollen compiliert werden, werden C++-Templates erstmal garnicht instantiiert, sondern erst dann, wenn sie benutzt werden, und dann auch nur für den einen Typ, mit dem sie benutzt werden. Und erst dann wird geprüft, ob der Code im Template überhaupt mit dem entsprechenden Typ compilierbar ist, d.h. ob die entsprechenden Operationen vorhanden sind.
-
Vielleicht hilft es dir, wenn du dir den C++ Template Mechanismus etwas einfacher vorstellst. Es ist im Grunde ein Luxus Präprozessor. Wenn du jetzt eine Funktion hast, die so aussieht:
template <typename T> bool are_equal(T const& a, T const& b) { return a == b; }Nimmst du jetzt int als Parameter wir daraus vom Kompiler:
bool are_equal<int>(int const& a, int const& b) { return a == b; }Alles Ok. Kompiliert also. Jetzt nimmst du einen Typen der nicht vergleichbar ist.
bool are_equal<Foo>(Foo const& a, Foo const& b) { return a == b; }Da Foo keinen
operator ==hat, gibt der Kompiler einen Fehler aus.Wenn du bei Templates noch keinen genauen Typen angibst, wird nur ein rudimentärer Syntaxcheck durchgeführt. Da der Kompiler nicht wissen kann, ob ein generischer Typ vergleichbar ist, oder nicht, zeigt er zu dem Zeitpunkt keinen Fehler an.
Gruß
Don06
-
pumuckl schrieb:
Nein, genau andersrum. Ganz im Gegensatz zu den Java Generics, die einmalig und sofort für alle Typen die rein können sollen compiliert werden, werden C++-Templates erstmal garnicht instantiiert, sondern erst dann, wenn sie benutzt werden, und dann auch nur für den einen Typ, mit dem sie benutzt werden. Und erst dann wird geprüft, ob der Code im Template überhaupt mit dem entsprechenden Typ compilierbar ist, d.h. ob die entsprechenden Operationen vorhanden sind.
Das ist auch der Grund warum man conventionen wie Traits, Concepts u.ä. hat.
Templates sind wie ziemlich dumme schablonen:
Es ist dem Compiler völlig egal ob der operator== oder der operator< überhaupt das tut was man von ihm will. Solange der Typ in die Schablone passt, sprich diese beiden Operatoren interstützt, wird der code compilieren.template<class Zahl> Zahl add(Zahl& a, Zahl& b) { return a+=b; }add wird für alles generiert was den operator+(T) definiert, völlig egal was es ist. std::string z.b. definiert diesen Operator auch!
D.h. ich kann hier statt einem Zahlentyp auch schreiben:int a, b; add("a", "b") ///!!! std::cout << add(a=1,b=2) << add(std::string("a"), std::string("b")).c_str() << std::endl;(ich weis das += mutet komisch an, aber mit nur a+b hat der compi gemeckert und ich wollt mich mit ihm grad nicht auseinandersetzen)
Sieh dir vielleicht mal das hier an (Punkt Concepts):
http://www.sgi.com/tech/stl/stl_introduction.html