Ihr Lieben,
ich benutze CubeIDE um STM32 Prozessoren zu bespaßen. Es gelang mir mit
#include <complex.h> und "float complex z;" die Rechnung mit komplexen
Zahlen in C++ komfortabel zu machen, vorher hatte ich das hingefummelt.
Das gleiche möchte ich jetzt mit 3D-Vektoren machen. Ich möchte also
dass der Compiler "float vector v;" versteht.
Welches include brauche ich denn dafür?
THX
Cheers
Detlef
C++ hat keine integrierten Klassen für Vektoren fixer Länge (valarray
ist für dynamische Länge). Du musst es dir selbst implementieren oder
eine der Millionen Bibliotheken für lineare Algebra nutzen.
Rbx schrieb:> Im K&R-C-Buch steht drin, wie man Header-Dateien anlegt oder Wikipedia> ist auch ganz gut:
Da steht aber nur C drin. In C++ gibt es exzellente Möglichkeiten,
solche Dinge zu kapseln und komfortabel nutzbar zu machen. Das ist zwar
auch eine nette Übung, erfindet aber das Rad zum tausendsten Mal neu,
denn Algebra-Bibliotheken gibt es sehr viele, z.B. Eigen. Fortran ist
hier allerdings total unhilfreich.
Es werden ja vermutlich auf dem Controller keine allzu komplexen
Algorithmen benötigt. Wichtiger ist daher ein übersichtliches und gut
nutzbares API.
Detlef _. schrieb:> ich benutze CubeIDE um STM32 Prozessoren zu bespaßen. Es gelang mir mit> #include <complex.h> und "float complex z;" die Rechnung mit komplexen> Zahlen in C++ komfortabel zu machen, vorher hatte ich das hingefummelt.
Das ist allerdings eigentlich der C-Weg. Da es dort keine Klassen gibt,
hat man das fest in den Sprachkern integriert. In C++ gibt es dafür
std::complex:
https://en.cppreference.com/w/c/numeric/complex/complexhttps://en.cppreference.com/w/cpp/numeric/complex> Das gleiche möchte ich jetzt mit 3D-Vektoren machen. Ich möchte also> dass der Compiler "float vector v;" versteht.> Welches include brauche ich denn dafür?
So etwas gibt es nicht. Es gäbe in C++ die Möglichkeit, ein
std::array<float, 3> zu erzeugen, aber da gibt es keine mathematischen
Operationen. Ein std::valarray<float> könnte man auch verwenden, aber
das hat eine dynamische Größe, die an der Stelle zu unnötigem Overhead
führt. Mathematische Operationen gibt es dafür, aber nur elementweise.
Am besten erzeugst du entweder selbst eine Klasse für deinen 3D-Vektor,
oder du suchst dir eine, die schon fertig ist und kann, was du brauchst.
Hi,
das Entscheidende für mich sind die Operatoren, wenn man immer add(a,b)
schreiben muss wirds unübersichtlich.
Aber ich habs hingekriegt, vielleicht nicht schön, aber geht und ist
nach 50Jahren C vllt. die zarte Pflanze der neuen Liebe zu C++.
Da ist bestimmt noch ne Macke drin, ich habs nur etwas getestet, also
Vorsicht.
Und noch Fragen an die Kundigen:
Die Komponenten des Vektors sind jetzt float. Wie kann man das variabel
machen sodass man float vec_t a und double vec_t b schreiben kann? Die
skalaren Rückgabewerte sollten dann auch entsprechend sein.
Für const mal vector und vector mal const definiere ich ja jeweils einen
eigenen Operator. Geht das auch eleganter?
Cheers
Detlef
Niklas G. schrieb:> Fortran ist> hier allerdings total unhilfreich.
Es geht hier gar nicht um Fortran. Nur standen viele gute
Programierhilfen zum Thema Mathe und Computer eben in Fortranbüchern.
Niklas G. schrieb:> Du musst es dir selbst implementieren oder> eine der Millionen Bibliotheken für lineare Algebra nutzen.
Das mit den "Millionen von Bibliotheken" ist auch nicht sonderlich
hilfreich. Selbst wenn man das macht: bis man sich da durchgewurschtelt
hat, hat man längst die technischen Sachen aus den Büchern
abgeschrieben. Das dauert nämlich nicht lange.
Wie man das ganze in C++ umsetzt, sollte man schon selber wissen, wenn
man es nutzt ;)
Da C++ recht verbreitet ist, könnte man schauen, ob das Internet was im
Angebot hat, was nützlich sein könnte:
(u.a.)
https://www.geeksforgeeks.org/how-to-initialize-3d-vector-in-cpp-stl/https://stackoverflow.com/questions/9812411/trying-to-create-a-3-dimensional-vector-in-chttps://gist.github.com/rishav007/accaf10c7aa06135d34ddf3919ebdb3b
..ein Testprogramm sollte man dazu wohl auch noch haben.
Detlef _. schrieb:> Die Komponenten des Vektors sind jetzt float. Wie kann man das variabel> machen sodass man float vec_t a und double vec_t b schreiben kann?
Sowas?
Rbx schrieb:> Nur standen viele gute> Programierhilfen zum Thema Mathe und Computer eben in Fortranbüchern.
Wie gesagt sind die Algorithmen ziemlich simpel. Ist auch an Detlef's
Antwort zu sehen. Ich brauche keine Fortran-Texte um eine
Vektor-Addition zu implementieren. Ganz davon abgesehen dass kaum noch
wer Fortran kann.
Rbx schrieb:> Selbst wenn man das macht: bis man sich da durchgewurschtelt> hat, hat man längst die technischen Sachen aus den Büchern> abgeschrieben.
Gute Bibliotheken haben intuitive APIs, wie man "a+b" hinschreibt muss
man nicht lange recherchieren.
Rbx schrieb:> Wie man das ganze in C++ umsetzt, sollte man schon selber wissen, wenn> man es nutzt ;)
GENAU das war aber die Frage. NICHT wie man eine Vektoraddition
implementiert, sondern wie die Struktur drumherum ist.
Rbx schrieb:> https://www.geeksforgeeks.org/how-to-initialize-3d-vector-in-cpp-stl/> https://stackoverflow.com/questions/9812411/trying-to-create-a-3-dimensional-vector-in-c
Benutzt beides std::vector, was hier völlig falsch ist.
Rbx schrieb:> https://gist.github.com/rishav007/accaf10c7aa06135d34ddf3919ebdb3b
Geht tatsächlich in die richtige Richtung, aber nicht besonders toll
gemacht. Das hat Detlef schon besser hinbekommen.
Detlef _. schrieb:> Die Komponenten des Vektors sind jetzt float. Wie kann man das variabel> machen sodass man float vec_t a und double vec_t b schreiben kann? Die> skalaren Rückgabewerte sollten dann auch entsprechend sein.
Ein Template draus machen. Dann wäre es vec_t<float> a und vec_t<double>
b.
Ich würde das etwa so schreiben:
1
template<typenameT>
2
classvec_t
3
{
4
public:
5
constexprvec_t()=default;
6
constexprvec_t(Tx1,Ty1,Tz1)
7
:x{x1},y{y1},z{z1}
8
{}
9
10
private:
11
Tx{},y{},z{};
12
};
Den Copy-Konstruktor braucht es nicht. Der wird automatisch erzeugt.
Die ganzen Operatoren für double und int braucht es auch nicht. Man kann
diese Typen auch ohne übergeben, und sie werden dann implizit
konvertiert.
> Für const mal vector und vector mal const definiere ich ja jeweils einen> eigenen Operator. Geht das auch eleganter?
Nein, aber da diese Multiplikation kommutativ ist, kannst du auch
schreiben:
1
vec_toperator*(constvec_t&veca,constfloatval){
2
returnval*veca;}
Ich würde aber hier einfach den operator*= definieren und dann darauf
basierend den operator*:
Rbx schrieb:> Das mit den "Millionen von Bibliotheken" ist auch nicht sonderlich> hilfreich. Selbst wenn man das macht: bis man sich da durchgewurschtelt> hat, hat man längst die technischen Sachen aus den Büchern> abgeschrieben. Das dauert nämlich nicht lange.
Famous last words...
Oliver
Hallo,
vielen Dank. Ich habe mal Johanns Vorschlag bearbeitet und kann jetzt
Vektoren mit variablen Komponenttypen erzeugen.
1
template<typenameT>
2
classvec_t
3
{
4
public:
5
typedefTelement_type;
6
Tx,y,z;
7
vec_t():vec_t(0,0,0){}// Oder std::nan
8
vec_t(constT&x,constT&y,constT&z)
9
:x(x),y(y),z(z){}
10
vec_toperator+(constvec_t&w)const
11
{
12
returnvec_t(x+w.x,y+w.y,z+w.z);
13
}
14
};
15
16
vec_t<float>v1{1,3,4};
17
vec_t<double>v2{1,3,4};
18
vec_t<double>w=v1+v2+vec_t<float>{1,2,3};
Die letzte Zeile gibt mir aber einen Syntax error, weil der + Operator
vect_t<double> und vect_t<float> nicht verheiraten mag.
Wie gehtn das?
THX
Cheers
Detlef
Ich will nix händisch konvertieren, dann muss ich ja jedes Mal überlegen
ob es double, float oder integer ist.
In C kann ich schreiben
double d = 3.0 +2.0f;
und muss nicht schreiben
double d = 3.0 + (double)2.0f
Cheers
Detlef
Detlef _. schrieb:> Ich will nix händisch konvertieren,
Musst du ja nicht.
Genau wie:
Rolf M. schrieb:> template<typename U>> vec_t(const vec_t<U>& v) : x(v.x), y(v.y), z(v.z) {}
kannst du auch die Operatoren als Template implementieren, und es
funktioniert solange die verwendeten Rechenschritte mit den Typen "U"
und "T" ausführbar sind.
Detlef _. schrieb:> Ich will nix händisch konvertieren, dann muss ich ja jedes Mal überlegen> ob es double, float oder integer ist.
Solange du den Konvertierkonstruktor nicht als explicit deklarierst,
musst du das auch nicht. Hast du meinen Code mal ausprobiert?`
Hallo Ernst,
vielen Dank, das Beispiel geht komplett, insbesondere:
vec_t<double> z=(a+b+c);
Aber das geht nicht:
vec_t<double> z=(b+a+c);
also b+a statt a+b :))))))
"conversion from 'vec_t<float>' to non-scalar type 'vec_t<double>'
requested.
Was issn da los?
Vielen Dank
Cheers
Detlef
Rolf M. schrieb:> Detlef _. schrieb:
Hast du meinen Code mal ausprobiert?`
Hallo Rolf, ich habe aus deinem Code nix Übersetzbares basteln können.
Ich habe zu wenig verstanden um die fehlenden Teile zu erstellen.
Cheers
Detlef
Detlef _. schrieb:> Hallo Rolf, ich habe aus deinem Code nix Übersetzbares basteln können.> Ich habe zu wenig verstanden um die fehlenden Teile zu erstellen.
Da fehlt nichts. Du musst einfach die von mir geposteten beiden Zeilen
in die in Beitrag "Re: complex und 3D Vektoren in C++ für ARM und STM32" gezeigte
Klasse einfügen, und dann sollte das alles funktionieren.
Detlef _. schrieb:> also b+a statt a+b :))))))>> "conversion from 'vec_t<float>' to non-scalar type 'vec_t<double>'> requested.
Du brauchst zusätzlich den Konvertierungs-Konstruktor von Rolf.
Detlef _. schrieb:> vec_t<double> z=(a+b+c);
"a" ist vec_t<double>, die Addition behält den Typen von der linken
Seite.
d.H "a+b+c" wird auch zu einem vec_t<double>, der sich ohne
konvertierung in "z" speichern lässt.
> Aber das geht nicht:> vec_t<double> z=(b+a+c);
"b+a+c" behält den typ von "b", also float-vector. den in z zu speichern
erfordert eine Konvertierung.
Wenn du wirklich mit gemischten Typen arbeiten willst, ist es evtl.
besser das nicht immer nach "Typ vom ersten Parameter gewinnt" zu
machen.
z.B. mit Template-Spezialisierungen, die festlegen dass immer der
größere Typ als Resultat rauskommt, double+float => double, float+double
=> double usw.
Ah, ok,
ich habe Rolfs Konvertierungskonstruktor eingebaut, dann ging auch
vec_t<double> z=(b+a+c);
Dann wollte ich den + Operator als Vorzeichen einbauen, also dass sowas
geht:
vec_t<float> b(4,5,6);
vec_t<double> d=(+b);
Dazu habe ich gebastelt mit nochmal Operator + :
1
template<typenameT>
2
classvec_t
3
{
4
public:
5
typedefTelement_type;
6
Tx,y,z;
7
//vec_t () : vec_t (0, 0, 0) {} // Oder std::nan
8
vec_t(constT&x,constT&y,constT&z)
9
:x(x),y(y),z(z){}
10
11
template<typenameU>
12
vec_t(constvec_t<U>&v):x(v.x),y(v.y),z(v.z){}
13
14
template<typenameU>
15
vec_toperator+(constvec_t<U>&w){
16
returnvec_t(x+w.x,y+w.y,z+w.z);
17
}
18
19
template<typenameU>
20
vec_toperator+(constvec_t<U>&w){
21
returnvec_t(w.x,w.y,w.z);
22
}
23
};
Das zweite Operator+ Ding liefert mir den Syntax error "template <class
T> template <class U> vec_t<T> vec_t<T>::operator+(const vec_t<U>&)
cannot be overloaded with template<class T> template<class U> vec_t<T>
vec_t<T>:: operator+(const vec_t<U> &)"
Verstehen tu ich nix mehr, könnt Ihr mir den Vorzeichenoperator + fixen
pls. .
Vielen Dank
Cheers
Detlef
Naja, schau dir die Deklarationen der beiden Operatoren an. Die sind
exakt gleich. Das wäre so, als ob du void foo(int x) mit void foo(int x)
überladen willst. Das geht natürlich nicht.
Dein unärer Operator + darf keinen Parameter haben. Als input hat er ja
schon das this-Objekt, das du in deiner Implementation gar nicht
verwendest.
Dadurch bekommt der Ergebnis-Vektor automatisch den Typ der
Element-Addition und das sollte immer der Größere sein (also
vec_t<float> + vec_t<double> = vec_t<double>). Außerdem hat das den
Vorteil, dass dieser Overload automatisch nicht berücksichtigt wird,
wenn die Typen nicht addiert werden können (SFINAE), und man ggf. auch
noch speziellere Overloads hinzufügen kann.
Außerdem:
1
template<typenameU>
2
vec_t(constvec_t<U>&v):x(v.x),y(v.y),z(v.z){}
Suggeriert dem Compiler dass alles in alles konvertierbar ist, und wenn
nicht gibt es kryptische Fehlermeldungen (vermutlich insbesondere in
Kombination mit der Addition). Wieder per SFINAE kann man diesen
Konstruktor für nicht-konvertierbare Typen deaktivieren:
IIRC bewirken die geschweiften Klammern in der Initialisierung auch mehr
Warnungen bei Präzisionsverlust.
Man könnte auch noch eine freie Funktion definieren um Vektoren zu
casten:
machen, was auch den potentiell etwas gefährlichen
Konvertierungs-Konstruktor vermeiden würde (eventueller
Präzisionsverlust wäre somit explizit).
PS: Diese ganzen fiesen Details sind der Grund, warum man eine fertige
Bibliothek nutzt.
>> Die letzte Zeile gibt mir aber einen Syntax error, weil der + Operator> vect_t<double> und vect_t<float> nicht verheiraten mag.>> Wie gehtn das?
Eine Möglichkeit ist ein Cast-Operator zu implementieren, so dass man
vec<float> nach vec<double> casten kann.
Rolf M. schrieb:> Naja, schau dir die Deklarationen der beiden Operatoren an. Die sind> exakt gleich. Das wäre so, als ob du void foo(int x) mit void foo(int x)> überladen willst. Das geht natürlich nicht.> Dein unärer Operator + darf keinen Parameter haben. Als input hat er ja> schon das this-Objekt, das du in deiner Implementation gar nicht> verwendest.
Ah, das verstehe ich.
Das geht jetzt syntaktisch durch
1
template<typenameT>
2
classvec_t
3
{
4
public:
5
typedefTelement_type;
6
Tx,y,z;
7
//vec_t () : vec_t (0, 0, 0) {} // Oder std::nan
8
vec_t(constT&x,constT&y,constT&z)
9
:x(x),y(y),z(z){}
10
11
template<typenameU>
12
vec_t(constvec_t<U>&v):x(v.x),y(v.y),z(v.z){}
13
14
template<typenameU>
15
vec_toperator+(){
16
returnvec_t(x,y,z);
17
}
18
template<typenameU>
19
vec_toperator+(constvec_t<U>&w){
20
returnvec_t(x+w.x,y+w.y,z+w.z);
21
}
22
};
Er meckert aber verhalten und ohne Error bei den beiden Operatorzeilen:
"template argument deduction/substitution failed"
Das aber scheitert:
vec_t<double> a(1,2,3);
vec_t<double> d= +a;
"no match for 'operator+' (operand type is 'vec_t<double>'
Was muss ich denn bei der Klasse ändern dass das durchläuft?
THX
Cheers
Detlef
Detlef _. schrieb:> "no match for 'operator+' (operand type is 'vec_t<double>'> Was muss ich denn bei der Klasse ändern dass das durchläuft?
Dein unary + Operator darf keinen Template-Parameter "U" nehmen.
Also einfach die template-Zeile davor rausnehmen.
Und die Compiler-Warnings anschalten, das erzählt der nämlich selbst..
>> couldn't deduce template parameter 'U'
Εrnst B. schrieb:> Detlef _. schrieb:>> "no match for 'operator+' (operand type is 'vec_t<double>'>> Was muss ich denn bei der Klasse ändern dass das durchläuft?>> Dein unary + Operator darf keinen Template-Parameter "U" nehmen.>> Also einfach die template-Zeile davor rausnehmen.>>> Und die Compiler-Warnings anschalten, das erzählt der nämlich selbst..>>> couldn't deduce template parameter 'U'
Ja, vielen Dank, das geht jetzt. Der - Operator geht auch. Der *
Operator soll das Skalarprodukt liefern. Wenn ich dem sage, dass er
float zurückliefern soll geht das auch, siehe Code. Wie kann ich dem *
Operator jetzt aber sagen, dass er mir den Typ der Eingangsvektoren
zurückliefert?
THX
Cheers
Detlef
In den meisten Fällen operiert man mit Vektoren über den selben
Skalaren, also: einfach:
1
>Toperator*(constvec_t&w)const
2
>{
3
>returnx*w.x+y*w.y+z*w.z;
4
>}
Wenn man unterschiedliche Typen mischen will wird's fix unübersichtlich,
zum Beispiel
int * float -> float
int * int -> int
float * float -> float
Das "Problem" hast du dann überall: Addition, Multiplikation
(Skalarprodukt, Kreuzprodukt, S-Multiplikation).
Ein Weg ist, den Typen eine "Priorität zuzuordnen, und als Ergebnistyp
denjenigen mit der höchsten Prio zu wählen:
short -> 1
int -> 2
long -> 3
float -> 4
double -> 5
und wenn Complex im Spiel ist oder Polynome wird's nochmal spaßiger.
Johann L. schrieb:> In den meisten Fällen operiert man mit Vektoren über den selben> Skalaren, also: einfach:>> T operator * (const vec_t &w) const>> {>> return x*w.x + y*w.y + z*w.z;>> }
Hi, funktioniert tadellos.
1
template<typenameT>
2
classvec_t
3
{
4
public:
5
typedefTelement_type;
6
Tx,y,z;
7
//vec_t () : vec_t (0, 0, 0) {} // Oder std::nan
8
vec_t(constT&x,constT&y,constT&z)
9
:x(x),y(y),z(z){}
10
11
template<typenameU>
12
vec_t(constvec_t<U>&v):x(v.x),y(v.y),z(v.z){}
13
14
vec_toperator+(){returnvec_t(x,y,z);}
15
16
template<typenameU>
17
vec_toperator+(constvec_t<U>&w){
18
returnvec_t(x+w.x,y+w.y,z+w.z);
19
}
20
21
template<typenameU>
22
vec_tcross(constvec_t<U>&w){
23
returnvec_t(y*w.z-z*w.y,
24
z*w.x-x*w.z,
25
x*w.y-y*w.x);}
26
27
Tnorm(constvec_t&w){
28
return(sqrt(w*w));}
29
30
vec_toperator-(){returnvec_t(-x,-y,-z);}
31
32
template<typenameU>
33
vec_toperator-(constvec_t<U>&w){
34
returnvec_t(x-w.x,y-w.y,z-w.z);}
35
36
Toperator*(constvec_t&w)const
37
{returnx*w.x+y*w.y+z*w.z;}
38
39
};
Sowas
vec_t<double> aa(1,2,3);
vec_t<double> ab(1,2,3);
float ac = (aa*ab);
double ad = (aa*ab);
funzt super.
In die Klasse habe ich noch das Kreuzprodukt cross und die norm
reingebastelt. Das geht auch syntaktisch so durch wie geschrieben.
Die Zeilen
double ae = vec_t.norm(aa);
vec_t<double> af = vec_t.cross(aa*ab);
liefern aber Syntaxfehler 'missing template arguments before . token'
Wie muss ich cross und norm denn mit dem template aufrufen?
THX
Cheers
Detlef
Detlef _. schrieb:> Wie muss ich cross und norm denn mit dem template aufrufen?
double ae = aa.norm();
vec_t<double> af = aa.cross(ab);
und dein "norm" im Template darf keinen Parameter nehmen.
Ihr Lieben,
vielen Dank. Angehängt main.cpp
Geht alles, wahrscheinlich. Die Syntax der typagnostischen Klasse für
3d Vektoren vec_t ist mir aber zu kryptisch und unschön um sie zu
verwenden. Ausserdem liefert dabei norm von integer Vektoren irgendwas
aber kein double oder float zurück. Wie würde das denn gehen?
Deswegen habe ich die Klasse für float 3D Vektoren zu fvec_t umbenannt
und recycelt. Die werde ich verwenden, float reicht in meinem Fall.
Beide Klassen habe ich getestet, naja, siehe code.
Sehr angenehm und ungewöhnlich auch dass der thread nicht verspamt oder
vertrollt wurde.
Cheers
Detlef
Bei all den Operatoren fehlt noch ein const, weil *this ja nicht
verändert wird (im Gegensatz zu += etc.).
Außerdem ist der % Operator frei, kann mal also für's Kreuzprodukt
nehmen. Leider kann man in C++ keine neuen Operatoren definieren wie
etwa in R.
Johann L. schrieb:> Bei all den Operatoren fehlt noch ein const, weil *this ja nicht> verändert wird (im Gegensatz zu += etc.).
Wo mussn das rein? Gab entweder bei der definition oder dem Aufruf
error. Von der template Geschichte hab ich so gut wie nix verstanden.
> Außerdem ist der % Operator frei, kann mal also für's Kreuzprodukt> nehmen. Leider kann man in C++ keine neuen Operatoren definieren wie> etwa in R.
Hab ich in beide Versionen eingebaut.
Cheers
Detlef
Was ich da nicht verstehe:
Warum sind für fvec_t die Operationen als Funktionen implementiert
anstatt als Methoden so wie im Klassentemplate.
Außerdem: Wenn man ein funktionierendes Vec<typename> hat, dann geht
doch einfach
1
usingfvec_t=vec_t<float>;
oder nicht?
Was ich am Klassentemplate nicht so schön finde ist, dass Operatoren wie
* nicht kommutatiiv sind, weil float * double einen double liefert,
double * float hingegen nen float (bzw. Vektoren darüber).
Und das Zeug könnte man noch constexpr machen und auch Operatoren für
Streams überladen.
Johann L. schrieb:> Was ich da nicht verstehe:>> Warum sind für fvec_t die Operationen als Funktionen implementiert> anstatt als Methoden so wie im Klassentemplate.>
Hatte ich so implementiert irgendwo aus dem web gezogen. Gab da eine
breite Einlassung mit 'friends', lag weit jenseits meines jetzigen C++
Horizonts.
Ich benötige für umfangreiche Vektoralgebra eine klare Syntax, weil ich
sonst die Fehler nicht finde. Das funktioniert mit fvect_t besser als
mit vec_t. Syntax mit vect_t ist total kontraintuitiv und zerrissen, da
könnte ich auch so weitermachen wie bisher mit addvec(a,b) für die
Addition zweier Vektoren als structs.
Kannst Du mal ein Beispiel machen wie für fvec_t Operatoren in der
Klasse implementiert werden?
> Außerdem: Wenn man ein funktionierendes Vec<typename> hat, dann geht> doch einfach>>
1
usingfvec_t=vec_t<float>;
>> oder nicht?>
Keine Ahnung, null Schimmer was using bedeutet und was Du tun willst.
Kannst Du ein Beispiel posten?
> Was ich am Klassentemplate nicht so schön finde ist, dass Operatoren wie> * nicht kommutatiiv sind, weil float * double einen double liefert,> double * float hingegen nen float (bzw. Vektoren darüber).
Ja, Schönheit und Kommutativität. Man benötigt verschiedene Operatoren
für const*vec und vec*const. Das ist weder schön noch kommutativ. Aber
wenigstens funktionierts'.
> Und das Zeug könnte man noch constexpr machen und auch Operatoren für> Streams überladen.
??. Benötige auch ein Beispiel. Was ist ein stream im C++ Kontext?
Cheers
Detlef
Detlef _. schrieb:> Hatte ich so implementiert irgendwo aus dem web gezogen. Gab da eine> breite Einlassung mit 'friends', lag weit jenseits meines jetzigen C++> Horizonts.
friend ist eigentlich recht simpel. Wenn man eine freistehende Funktion
schreiben will, die direkt auf Members einer Klasse zugreifen können
soll, die eigentlich private sind, dann kann man das erreichen, indem
man die Funktion zu einem friend der Klasse macht. Das kann gerade bei
den Operatoren hilfreich sein.
> Ich benötige für umfangreiche Vektoralgebra eine klare Syntax, weil ich> sonst die Fehler nicht finde. Das funktioniert mit fvect_t besser als> mit vec_t.
Wieso? Die ist doch eigentlich gleich. Und letztendlich war es ja deine
Anforderung, für jede Instanz den Elementtyp wählen zu können. Wenn es
sowieso am Ende immer nur float sein soll. kannst du dir die Templaterei
auch ganz sparen.
> Syntax mit vect_t ist total kontraintuitiv und zerrissen, da> könnte ich auch so weitermachen wie bisher mit addvec(a,b) für die> Addition zweier Vektoren als structs.
Hast du mal ein Beispiel, wo die im Vergleich zu deinem fvect
"zerrissen" ist?
> Kannst Du mal ein Beispiel machen wie für fvec_t Operatoren in der> Klasse implementiert werden?
Was brauchst du da für ein Beispiel? Es funktioniert ohne Template genau
gleich wie mit Template, und da hast du es doch hinbekommen.
>> Außerdem: Wenn man ein funktionierendes Vec<typename> hat, dann geht>> doch einfach>>>>using fvec_t = vec_t<float>;>>>> oder nicht?>>>> Keine Ahnung, null Schimmer was using bedeutet und was Du tun willst.
Ein Typ-Alias erstellen. Das ist das gleiche wie:
1
typedefvec_t<float>fvect_t;
Es führt dazu, dass du vec_t<float> auch als fvec_t benutzen kannst.
>> Was ich am Klassentemplate nicht so schön finde ist, dass Operatoren wie>> * nicht kommutatiiv sind, weil float * double einen double liefert,>> double * float hingegen nen float (bzw. Vektoren darüber).>> Ja, Schönheit und Kommutativität. Man benötigt verschiedene Operatoren> für const*vec und vec*const. Das ist weder schön noch kommutativ. Aber> wenigstens funktionierts'.
Wegen solchen Asymmetrien finde ich es übrigens besser, die Operatoren
wenn möglich nicht in der Klasse, sondern als freie Funktionen zu
implementieren. Bei den Konvertierungen gibt es sonst an machen Stellen
unterschiedliche Behandlung des linken und rechten Operanden, weil der
linke das this-Objekt ist. Bei einer freien Funktion sind sie
gleichwertig.
>> Und das Zeug könnte man noch constexpr machen und auch Operatoren für>> Streams überladen.>> ??. Benötige auch ein Beispiel. Was ist ein stream im C++ Kontext?
std::cin und std::cout sind z.B. Streams.
constexpr kann man verwenden, damit Berechnungen mit Konstanten auch
komplett zur Compilezeit durchgeführt und deren Ergebnisse als echte
Compilezeit-Konstanten verwendet werden können.
Ja, habe jede Menge C++ Bücher, von Stroustrup angefangen. Ich dachte
ich lerns' nicht mehr, aber die Operatoren für complex und jetzt für 3d
Vektoren machen C++ schon sehr attraktiv. Das geht in C nich. Ich bin
möglicherweise in der Lage sowas für Matrizen zu basteln, das wäre dann
sehr nützlich. Ich kenne IT++ und Genossen, aber das war mir immer
zuviel Overhead, das benötige ich nicht und krieg es auch nicht auf den
uC.
Cheers
Detlef
Hi,
den + Operator hatte ich ja:
fvec_t operator+(const fvec_t &veca, const fvec_t &vecb){
return fvec_t(veca.x+vecb.x,veca.y+vecb.y,veca.z+vecb.z);};
Wie geht denn der += Operator ?
THX
Cheers
Detlef
Hi,
das krieg ich so nicht übersetzt.
Der Operator
dvec_t operator+=(const double val){
x+=val;
y+=val;
z+=val;
return *this;
}
liefert
'dvec_t operator+=(double)' must have an argument of class or
enumerated type' für die erste Zeile.
So sieht die Klasse aus:
class dvec_t
{
public:
double x,y,z;
dvec_t(){x=0;y=0;z=0;}
dvec_t(double x1,double y1,double z1)
{x=x1;y=y1;z=z1;}
dvec_t(const dvec_t &vec){
x=vec.x;y=vec.y;z=vec.z;}
};
Ich dachte ich hätte einen Zipfel von C++, das war ein Irrtum.
Cheers
Detlef
dvec_t test1(1,2,3);
test1+=41;
// test1.x == 42
PS:
Ob du als Rückgabewert vom operator+= jetzt "const dvec_t&" oder nur
dvect_t nimmst, ist erstmal egal.
Achso, das Ding steht in der Klasse selbst. Das funzt.
Meine anderen Operatoren stehen immer ausserhalb der Klasse.
Wie krieg ich das denn ähnlich hin?
THX
Cheers
Detlef