Funktion mit Template als Argument
-
Hallo,
sehe ich das richtig, dass du damit im Wesentlichen das
inner_productnachgebaut hast?Gruß,
-- Klaus.
-
Klaus82 schrieb:
Hallo,
sehe ich das richtig, dass du damit im Wesentlichen das
inner_productnachgebaut hast?Gruß,
-- Klaus.inneres produkt == skalarprodukt == dot product. also hast du recht, ja.
-
Klaus82 schrieb:
Hallo,
sehe ich das richtig, dass du damit im Wesentlichen das
inner_productnachgebaut hast?Gruß,
-- Klaus.Ja, habe ich. Es sollte aber erstmal exemplarischer Natur sein, ich habe mir noch einge andere Funktionen wie Dyadisches- und Kreuzprodukt usw. gebastelt. Zudem ging es mir um eine Möglichkeit mich näher mit Templates zu befassen. Trotzdem danke für den Hinweis auf diese nette Funktion!

-
chmbw schrieb:
Danke für den Hinweis!
Ich habe jetzt folgendes:template <class Type> class Vector { public: Vector(Type x, Type y, Type z); template <typename T> friend T dotProduct(const Vector<T>& a, const Vector<T>& b); private: Type x; Type y; Type z; }; template <class Type> Type dotProduct(const Vector<Type>& a, const Vector<Type>& b) { return a.x * b.x + a.y * b.y + a.z * b.z; }Kleiner Tipp: Wenn du so ein "Muster" wie oben hast, dann mach dotProduct zu einer wirklich freien Funktion außerhalb und spendiere Vector eine Memberfunktion dotProduct:
Type Vector::dotProduct(const Vector<Type>& b) const { return x * b.x + y * b.y + z * b.z; } template <class Type> Type dotProduct(const Vector<Type>& a, const Vector<Type>& b) { return a.dotProduct(b); }Jetzt bist du erstmal friend los und hast noch ein paar weitere Vorteile. Wenn du mal zB von Vector eine weitere Klasse ableiten solltest, zB Vector4, dann kannst du diese freie Funktion immer noch verwenden. Ansonsten müsstest du für jede Hirarchie-Ebene eine weitere Funktion außerhalb implementieren. So ist Implementierung dann auch dort, wo sie von der Zuständigkeit her hingehört. In deinem VectorBase packst du dann noch ein virtual Type dotProduct() = 0; rein und alle nachfolgenden Klassen freuen sich auch. Mitunter hast du jetzt die Kapselung erhöht, da weniger Funktion von außen auf deinem Member zugreifen können und kannst das Programm auch schneller und wartungsfreier erweitern.
-
um friend loszuwerden müsste ich dann ja
Type Vector::dotProduct(const Vector<Type>& b) const { return x * b.x + y * b.y + z * b.z; }als public deklarieren. Wenn ich jetzt allerdings nur die externe Funktion
template <class Type> Type dotProduct(const Vector<Type>& a, const Vector<Type>& b) { return a.dotProduct(b); }zulassen möchte, muss ich diese doch wieder als friend in der Vektorklasse angeben, oder nicht?!
-
KasF schrieb:
Kleiner Tipp: Wenn du so ein "Muster" wie oben hast, dann mach dotProduct zu einer wirklich freien Funktion außerhalb und spendiere Vector eine Memberfunktion dotProduct:
Type Vector::dotProduct(const Vector<Type>& b) const { return x * b.x + y * b.y + z * b.z; } template <class Type> Type dotProduct(const Vector<Type>& a, const Vector<Type>& b) { return a.dotProduct(b); }Schwachsinn.
Wo ist Dein Muster nochmal passend? Beim operator<<(ostream&,Foo) zusammen mit virtual Foo::printAt(ostream&). Das heißt aber noch lange nicht, daß Dein Muster auf jedes Problem passt.KasF schrieb:
Jetzt bist du erstmal friend los und hast noch ein paar weitere Vorteile.
Jo, friend ist weg, und die Schnittstelle ist nicht mehr minimal, die Methode muss wieder private werden und das friend muss wieder hin. Und dotProduct hat auf einmal ein this, das Subjekt, den Täter, was nicht gut passt, diese Lüge muss aus der Schnittstelle raus. Deswegen kann man in http://www.c-plusplus.net/forum/324787 sich nicht mit 45 Minuten beschränken.
KasF schrieb:
Wenn du mal zB von Vector eine weitere Klasse ableiten solltest, zB Vector4, dann kannst du diese freie Funktion immer noch verwenden.
Achso! Ein Vector4 IST EIN Vector3 mit einem Element mehr. Die void retteWelt(Vector3 const&) kann ich beruhigt mit einem Vector4 aufrufen, wenn ich gerade keinen Vector3 zur Hand habe. Schwachsinn. "Herr Bebel…" lesen und nicht den Wolf.
KasF schrieb:
Ansonsten müsstest du für jede Hirarchie-Ebene eine weitere Funktion außerhalb implementieren.
Ex falso quod libet, woraus ich zu schließen beliebe, daß man für jede weitere Hierarchie-Ebene eben keine weitere Funktion außerhalb definieren muss.
KasF schrieb:
So ist Implementierung dann auch dort, wo sie von der Zuständigkeit her hingehört.
Nein. Was Templates getrennt haben, soll die Vererbung nicht zusammenführen.
KasF schrieb:
In deinem VectorBase packst du dann noch ein virtual Type dotProduct() = 0; rein und alle nachfolgenden Klassen freuen sich auch.
Ach nöö, das ist doch kein Java-Kindergarten hier.
KasF schrieb:
Mitunter hast du jetzt die Kapselung erhöht, da weniger Funktion von außen auf deinem Member zugreifen können und kannst das Programm auch schneller und wartungsfreier erweitern.
Ganz sicher hast Du mit dem sinnlosvererben die Abhängigkeiten erhöht und Dir eine Warungsbremse, wenn nicht gar eine Wartungsmauer gebaut. Wenn TyRoXx sowas jeden Tag sehen müßte, könnte ich seine generellen Ressentiments gegen Vererbung fast verstehen.
-
volkard schrieb:
KasF schrieb:
Kleiner Tipp: Wenn du so ein "Muster" wie oben hast, dann mach dotProduct zu einer wirklich freien Funktion außerhalb und spendiere Vector eine Memberfunktion dotProduct:
Type Vector::dotProduct(const Vector<Type>& b) const { return x * b.x + y * b.y + z * b.z; } template <class Type> Type dotProduct(const Vector<Type>& a, const Vector<Type>& b) { return a.dotProduct(b); }Schwachsinn.
Wo ist Dein Muster nochmal passend? Beim operator<<(ostream&,Foo) zusammen mit virtual Foo::printAt(ostream&). Das heißt aber noch lange nicht, daß Dein Muster auf jedes Problem passt.KasF schrieb:
Jetzt bist du erstmal friend los und hast noch ein paar weitere Vorteile.
Jo, friend ist weg, und die Schnittstelle ist nicht mehr minimal, die Methode muss wieder private werden und das friend muss wieder hin. Und dotProduct hat auf einmal ein this, das Subjekt, den Täter, was nicht gut passt, diese Lüge muss aus der Schnittstelle raus. Deswegen kann man in http://www.c-plusplus.net/forum/324787 sich nicht mit 45 Minuten beschränken.
KasF schrieb:
Wenn du mal zB von Vector eine weitere Klasse ableiten solltest, zB Vector4, dann kannst du diese freie Funktion immer noch verwenden.
Achso! Ein Vector4 IST EIN Vector3 mit einem Element mehr. Die void retteWelt(Vector3 const&) kann ich beruhigt mit einem Vector4 aufrufen, wenn ich gerade keinen Vector3 zur Hand habe. Schwachsinn. "Herr Bebel…" lesen und nicht den Wolf.
KasF schrieb:
Ansonsten müsstest du für jede Hirarchie-Ebene eine weitere Funktion außerhalb implementieren.
Ex falso quod libet, woraus ich zu schließen beliebe, daß man für jede weitere Hierarchie-Ebene eben keine weitere Funktion außerhalb definieren muss.
KasF schrieb:
So ist Implementierung dann auch dort, wo sie von der Zuständigkeit her hingehört.
Nein. Was Templates getrennt haben, soll die Vererbung nicht zusammenführen.
KasF schrieb:
In deinem VectorBase packst du dann noch ein virtual Type dotProduct() = 0; rein und alle nachfolgenden Klassen freuen sich auch.
Ach nöö, das ist doch kein Java-Kindergarten hier.
KasF schrieb:
Mitunter hast du jetzt die Kapselung erhöht, da weniger Funktion von außen auf deinem Member zugreifen können und kannst das Programm auch schneller und wartungsfreier erweitern.
Ganz sicher hast Du mit dem sinnlosvererben die Abhängigkeiten erhöht und Dir eine Warungsbremse, wenn nicht gar eine Wartungsmauer gebaut. Wenn TyRoXx sowas jeden Tag sehen müßte, könnte ich seine generellen Ressentiments gegen Vererbung fast verstehen.
Danke für deinen Beitrag, wie würdest du dann mein "Problem" lösen? So wie ich es vorher hatte mit:
template <class Type> class Vector { public: Vector(Type x, Type y, Type z); template <typename T> friend T dotProduct(const Vector<T>& a, const Vector<T>& b); private: Type x; Type y; Type z; }; template <class Type> Type dotProduct(const Vector<Type>& a, const Vector<Type>& b) { return a.x * b.x + a.y * b.y + a.z * b.z; }Danke im Voraus!
-
Mach x, y und z einfach
public.
Ansonsten kannst du versuchen mir zu erklären warum x, y und z eines Vektorsprivatesein sollten.
-
mir ist suspekt wieso es keine getter für die vektor-komponenten gibt.
ich nutze die gelegenheit um aus eigenem interesse nachzufragen:
vec2 / vec3 haben mit vec4 doch eigentlich nicht viel am hut, da das w-element aus vec4 nicht als neue komponente behandelt wird (also nicht so wie z bei vec2 -> vec3) weil es sich um homogene koordinaten handelt. sehe ich das richtig? daher finde ich allgemein den ansatz, vec alstemplate<typename T, std::size_t n>zu implementieren, ein wenig überdenkenswert. ist meine überlegung korrekt / gerechtfertigt?ich hab das problem, dass ich mir bei solchen modellierungsproblemen zu viele gedanken mache und dass mich nicht auf das wesentliche konzentrieren kann.
edit: wenn vec4 und vec3 nicht durch dieses klassentemplate (oben angedeutet) instanziiert werden, dann ist die frage, wie man das ganze möglichst generisch und ohne code-overhead realisieren kann.
-
chmbw schrieb:
Danke für deinen Beitrag, wie würdest du dann mein "Problem" lösen?
Ich sehe kein Problem.
chmbw schrieb:
So wie ich es vorher hatte mit:
template <class Type> class Vector { public: Vector(Type x, Type y, Type z); template <typename T> friend T dotProduct(const Vector<T>& a, const Vector<T>& b); private: Type x; Type y; Type z; }; template <class Type> Type dotProduct(const Vector<Type>& a, const Vector<Type>& b) { return a.x * b.x + a.y * b.y + a.z * b.z; }Jo, ist doch prima. Allenfalls noch unbedeutende Kleinigkeiten,
- den Konstruktorcode reinziehen, ist ja trivial,
- sie Vector3 nennen,
- die Kompunenten x,y,z darf eigentlich jeder lesen, der Lust drauf hat,
- dann brauchts auch kein friend mehr.
-
asfdlol schrieb:
mir ist suspekt wieso es keine getter für die vektor-komponenten gibt.
Gibt es, ich wollte nur nicht den kompletten Code posten weil ich es als wenig hilfreich bzgl. meiner Frage erachtet habe.
volkard schrieb:
Jo, ist doch prima. Allenfalls noch unbedeutende Kleinigkeiten,
- den Konstruktorcode reinziehen, ist ja trivial,
- sie Vector3 nennen,
- die Kompunenten x,y,z darf eigentlich jeder lesen, der Lust drauf hat,
- dann brauchts auch kein friend mehr.Alles klar. Auch wenn es wohl mehr eine Glaubensfrage zu sein scheint, was spricht gegen private und friend für x,y,z?! Natürlich kann ich alles public machen, aber ich möchte halt nicht, dass die Einträge direkt manipuliert werden. Oder gibt es eine "read only" Möglichkeit (Mal von Getter/Setter abgesehen)?
-
chmbw schrieb:
asfdlol schrieb:
mir ist suspekt wieso es keine getter für die vektor-komponenten gibt.
Gibt es, ich wollte nur nicht den kompletten Code posten weil ich es als wenig hilfreich bzgl. meiner Frage erachtet habe.
lol. wieso dann friend usw.? die freie funktion kann auch so das skalarprodukt errechnen.
chmbw schrieb:
[...]was spricht gegen private und friend für x,y,z?!
unnötiger overhead.
chmbw schrieb:
Natürlich kann ich alles public machen, aber ich möchte halt nicht, dass die Einträge direkt manipuliert werden.
wieso nicht? wieso soll man instanzen der klasse vector nicht verändern dürfen? was würdest du sagen, wenn man floats nicht verändern darf?
chmbw schrieb:
Oder gibt es eine "read only" Möglichkeit (Mal von Getter/Setter abgesehen)?
die instanz const-qualifizieren.
-
chmbw schrieb:
Alles klar. Auch wenn es wohl mehr eine Glaubensfrage zu sein scheint, was spricht gegen private und friend für x,y,z?!
Type dist(Vector<Type> v1,Vector<Type> v2){ //Wollte echt nicht schon wieder chmbw anmailen, daß er nur für mich //noch eine Funktion bereitstellt. Daher nicht den normalen Weg über //_hypot2 genommen. return sqrt(dotProduct(v1-v2,v1-v2)); }chmbw schrieb:
Natürlich kann ich alles public machen, aber ich möchte halt nicht, dass die Einträge direkt manipuliert werden.
Jo, da hätte ich auch etwas dagegen.
chmbw schrieb:
Oder gibt es eine "read only" Möglichkeit (Mal von Getter/Setter abgesehen)?
Hat ich gerade Setter gehört?
Getter (ohne Setter) machen readonly, und ich kenne keinen anderen (noch einigermaßen sinnvollen) Weg.
-
asfdlol schrieb:
chmbw schrieb:
Natürlich kann ich alles public machen, aber ich möchte halt nicht, dass die Einträge direkt manipuliert werden.
wieso nicht? wieso soll man instanzen der klasse vector nicht verändern dürfen? was würdest du sagen, wenn man floats nicht verändern darf?
Die Komponenten der floats sind tabu.
Was haste davon, das vierzigste Bit umzuwerfen oder die Mantisse um 5 Positionen zu shiften?
-
[quote="volkard"]
chmbw schrieb:
Alles klar. Auch wenn es wohl mehr eine Glaubensfrage zu sein scheint, was spricht gegen private und friend für x,y,z?!
Type dist(Vector<Type> v1,Vector<Type> v2){ //Wollte echt nicht schon wieder chmbw anmailen, daß er nur für mich //noch eine Funktion bereitstellt. Daher nicht den normalen Weg über //_hypot2 genommen. return sqrt(dotProduct(v1-v2,v1-v2)); }
Dieses Zugriffproblem würde ja nicht mit Gettern auftreten (welche ich ja habe). Ich hätte halt nur einen entsprechenden Funktionsaufruf mehr (Overhead...)
-
chmbw schrieb:
Ich hätte halt nur einen entsprechenden Funktionsaufruf mehr (Overhead...)
Laufzeitoverhead oder verlorene Eintippzeit des Entwicklers?
-
volkard schrieb:
asfdlol schrieb:
chmbw schrieb:
Natürlich kann ich alles public machen, aber ich möchte halt nicht, dass die Einträge direkt manipuliert werden.
wieso nicht? wieso soll man instanzen der klasse vector nicht verändern dürfen? was würdest du sagen, wenn man floats nicht verändern darf?
Die Komponenten der floats sind tabu.
Was haste davon, das vierzigste Bit umzuwerfen oder die Mantisse um 5 Positionen zu shiften?ah, ich glaube, ich verstehe worauf du hinaus willst: dass float (& vec) ansich schon alle benötigten operationen anbietet (/ anbieten). vermute ich richtig?
wie ist das deiner erfahrung nach mit den compiler-optimierungen bei solchen komplexeren dingen? ich hab immer so ein schlechtes gewissen wenn ich eine temporäre translationsmatrix / skalierungsmatrix erstelle und sie mit einem vektor multipliziere statt dass ich einfach direkt die komponenten bearbeite.
-
volkard schrieb:
...
Erstmals, deine Großkotzige-Art kannst du dir sonst wohin stecken. Deine ständig herablassende Art und Götterkomplex verbreitet nur eine schlechte Athmosphäre hier im Forum. Das prädige ich dir schon seit Jahren, du verharrst aber stur. So machst du dir nicht viele wahre Freunde. Das Forum ist viel entspannter, wenn du mal wieder für ne längere Zeit verschwunden bist. Und so einer schmückt sich als Moderator! Lern erstmal einen anständigen Umgang mit deinen Forenmitglieder. Es ist echt
mit dir.Zweitens, zum deinen anderen "Kommentaren" nehme ich später Stellung.
-
Kapselung heisst nicht, alles private zu machen, was geht, sondern nur dort, wo es Sinn ergibt. Ein Vector gehoert bestimmt nicht dazu.
-
asfdlol schrieb:
volkard schrieb:
asfdlol schrieb:
chmbw schrieb:
Natürlich kann ich alles public machen, aber ich möchte halt nicht, dass die Einträge direkt manipuliert werden.
wieso nicht? wieso soll man instanzen der klasse vector nicht verändern dürfen? was würdest du sagen, wenn man floats nicht verändern darf?
Die Komponenten der floats sind tabu.
Was haste davon, das vierzigste Bit umzuwerfen oder die Mantisse um 5 Positionen zu shiften?ah, ich glaube, ich verstehe worauf du hinaus willst: dass float (& vec) ansich schon alle benötigten operationen anbietet (/ anbieten). vermute ich richtig?
Also float bietet alles an, insofern war Dein Beispiel schlecht gewählt.
Bei Vector fällt mir gar nix ein, wie man ihn per Hand inkonsistent machen kännte. Dann können x,y,z ruhig aufgemacht werden.asfdlol schrieb:
wie ist das deiner erfahrung nach mit den compiler-optimierungen bei solchen komplexeren dingen? ich hab immer so ein schlechtes gewissen wenn ich eine temporäre translationsmatrix / skalierungsmatrix erstelle und sie mit einem vektor multipliziere statt dass ich einfach direkt die komponenten bearbeite.
Hab da auch ein schlechtes Gefühl, andererseits vertraue ich -O3 schon sehr, sodaß ich auch schnell zumache, wenn ich meine, dadurch Programmierfehler verhindern zu können. Bei translationsmatrix/skalierungsmatrix bin ich nicht frisch genug im Thema, würde vielleicht erstmal überlegen, ob die Klassen Translationsmatrix/Skalierungsmatrix (die die bei 1-Feldern bzw 0-Feldern an compilezeitbekannten Positionen die Multiplikation weglassen) taugen würden (und vermutlich trotzdem aufmachen).