Kommutativität von Operatorüberladungen ;)
-
Hi,
schreibe gerade an einer templatebasierten Matrizen-Klasse und möchte die Multiplikation mit einem Skalar implementieren.
Aus früheren Versuchen weiß ich, dass eine nicht-Klassenmember Implementierung à la
/* multiplication with scalars */ template <class T> Matrix<T> operator*( const T& scalar, const Matrix<T>& matrix );Probleme bei Vererbung gibt.
Insbesondere existiert ein weiteres unschönes Problem:Matrix<float> A(3,3) = ...; 3*A;funktioniert nicht, da er keinen entspr. Operator findet weil die 3 nicht zu 3.f gecastet wird. Ließe sich zwar mit manuellem Casting oder Implementierung von Überladungen mit anderen Datentypen realisieren, schön ist das aber nicht wirklich.
Insbesondere wenn die Klasse mit selbst definierten Datentypen (Komplexe Zahlen?) umgehen können soll.Daher bevorzuge ich folgende Variante:
template <class T> Matrix<T> Matrix<T>::operator*( const T& scalar ) constFunktioniert auch soweit einwandfrei, aber leider nur in eine Richtung.
A*3 klappt, 3*A nicht.Kann ich irgendwie einen Klassenmember-Operator definieren, der den Skalar als linksseitiges Argument akzeptiert?
Thx in advance

-
hasu schrieb:
Kann ich irgendwie einen Klassenmember-Operator definieren, der den Skalar als linksseitiges Argument akzeptiert?
Nein, geht nicht.
hasu schrieb:
Aus früheren Versuchen weiß ich, dass eine nicht-Klassenmember Implementierung à la
/* multiplication with scalars */ template <class T> Matrix<T> operator*( const T& scalar, const Matrix<T>& matrix );Probleme bei Vererbung gibt.
Welche Probleme sollten das sein? Wenn du von Matrix ableitest musst du für die abgeleitete Klasse die Operatoren überladen. Andererseits haben Matrizen Wertsemantik und sollten eigentlich nicht abgeleitet werden.
hasu schrieb:
Insbesondere existiert ein weiteres unschönes Problem:
Matrix<float> A(3,3) = ...; 3*A;funktioniert nicht, da er keinen entspr. Operator findet weil die 3 nicht zu 3.f gecastet wird.
Verallgemeinere deinen Operator wie folgt:
template <class T> Matrix<T>& Matrix<T>::operator*=(T const& rhs) { /* Skalarmultiplikation hier iplementieren */ } template <class scalar_type, class T> Matrix<T> operator* (scalar_type const& lhs, Matrix<T> const& rhs) { Matrix<T> tmp(rhs); tmp *= lhs; return tmp; }Also wie üblich op*= als Member, op* mit Hilfe von op*= implementieren. In der zweiten Zeile
tmp *= lhsversucht der Compiler dann eine Typumwandlung von scalar_type nach T.Ich kann außerdem noch die Lektüre des Artikels zur Operatorüberladung empfehlen, und evtl. interessiert dich auch boost::operators

-
Hi, erstmal danke für die Antwort.
pumuckl schrieb:
Welche Probleme sollten das sein? Wenn du von Matrix ableitest musst du für die abgeleitete Klasse die Operatoren überladen. Andererseits haben Matrizen Wertsemantik und sollten eigentlich nicht abgeleitet werden.
Genau die erneut nötige Überladung der Operatoren für die Tochterklasse finde ich nervig. Es müssen alle Nichtmember-Operatoren neu geschrieben werden, was teilweise (ich hatte vorher fast alles als Nichtmember implementiert) in soviel Arbeit ausartet dass man sich die Ableitung fast ganz sparen kann.
Sinn können abgeleitete Klassen m.E. dennoch haben, im Falle von Matrizen bspw. alternative Datenspeicherungsmodelle für bestimmte Matrizenklassen (Diagonal-, Tridiagonal, Dreiecks-, symmetrische Matrizen). Oder bei Vektoren, die auch im Projekt implementiert sind, lohnt eine Definition des Kreuzprodukts i.d.R. nur für dim=3.
Was genau meinst du mit Wertsemantik, der Begriff sagt mir nichts.pumuckl schrieb:
Verallgemeinere deinen Operator wie folgt:
template <class T> Matrix<T>& Matrix<T>::operator*=(T const& rhs) { /* Skalarmultiplikation hier iplementieren */ } template <class scalar_type, class T> Matrix<T> operator* (scalar_type const& lhs, Matrix<T> const& rhs) { Matrix<T> tmp(rhs); tmp *= lhs; return tmp; }Also wie üblich op*= als Member, op* mit Hilfe von op*= implementieren. In der zweiten Zeile
tmp *= lhsversucht der Compiler dann eine Typumwandlung von scalar_type nach T.Das ist eine super Idee, danke!
pumuckl schrieb:
Ich kann außerdem noch die Lektüre des Artikels zur Operatorüberladung empfehlen, und evtl. interessiert dich auch boost::operators

Werd ich mir mal ansehen.