Problem mit template Operatoren
-
Hi,
folgendes:template<typename scal_type, const unsigned order> inline mat<scal_type, order, order>& operator*=( mat<scal_type, order, order>& lhs, const mat<scal_type, order, order>& rhs) { [...] return (lhs); } // binary operators template<typename scal_type, const unsigned order> inline mat<scal_type, order, order> operator*(const mat<scal_type, order, order>& lhs, const mat<scal_type, order, order>& rhs) { return (mat<scal_type, order, order>(lhs) *= rhs); }Dies funktioniert unter Windows mit dem Visual C++ 8.0 und 9.0 Compiler problemlos. Mit dem GCC leider nicht. Dieser ist der Meinung er findet den *= Operator nicht. Ändere ich es wie folgt ist alles i.O.:
// binary operators template<typename scal_type, const unsigned order> inline mat<scal_type, order, order> operator*(const mat<scal_type, order, order>& lhs, const mat<scal_type, order, order>& rhs) { mat<scal_type, order, order> tmp(lhs); return (tmp *= rhs); }Die Fehlermeldung sieht wie folgt aus. Was mich da stutzig macht ist das
das *)lhs). Denkt er da passiert ein cast und keine temporaere
Instanziierung?/home/chrislu/devel/schism_x64/schism_linux_x64/schism/build/cmake/../../src/scm/core/math/mat.inl:97: error: no match for ‘operator*=’ in ‘scm::math::mat<float, 4u, 4u>(((const scm::math::mat<float, 4u, 4u>&)((const scm::math::mat<float, 4u, 4u>*)lhs))) *= rhs’ /home/chrislu/devel/schism_x64/schism_linux_x64/schism/build/cmake/../../src/scm/core/math/mat.inl:37: note: candidates are: scm::math::mat<scal_type, order, order>& scm::math::operator*=(scm::math::mat<scal_type, order, order>&, const scm::math::mat<scal_type, order, order>&) [with scal_type = float, unsigned int order = 4u]Das ist mit dem gcc 4.1.1 unter x86 Linux und mit dem gcc 4.2.1 unter einem x84_64 Linux identisch.
-
Alle Compiler haben recht. Dein operator* kann nicht instantiiert werden, dieses Template ist daher ill-formed. Eine Diagnose ist aber nicht erforderlich (aber erlaubt und nat. wünschenswert) solange das Template nicht instantiiert wird.
mat<scal_type, order, order>(lhs) ist ein cast-Ausdruck, das Ergebnis ein rvalue. rvalues können nicht an non-const-Referenzen gebunden werden, folglich kann dieser Ausdruck nicht als linker Operand deines *= - Operators benutzt werden.
Besser als deine Lösung ist im Übrigen:// binary operators template<typename scal_type, const unsigned order> inline mat<scal_type, order, order> operator*(const mat<scal_type, order, order>& lhs, const mat<scal_type, order, order>& rhs) { mat<scal_type, order, order> tmp(lhs); tmp *= rhs; return tmp; }Nur so kann von der NRVO Gebrauch gemacht werden.
Nebenbei: der fehlerhafte Ausdruck wäre selbst dann ineffizient (kann nicht für RVO benutzt werden), wenn der Fehler nicht da wäre (also z.B. weil op*= als Memberfunktion überladen wurde).
-
Danke,
ich habe es nachgemessen, meine Version erfährt keine Optimierung während die Version von Dir wunderbar optimiert wird.Danke!
-
Hallo,
ich habe doch noch eine Frage zu der NVRO.template<typename scal_type> inline vec<scal_type, 4>& vec<scal_type, 4>::operator+=(const vec<scal_type, 4>& v) { x += v.x; y += v.y; z += v.z; w += v.w; return (*this); } // binary operators template<typename scal_type, typename scal_type_r> inline const vec<scal_type, 4> operator+(const vec<scal_type, 4>& lhs, const vec<scal_type_r, 4>& rhs) { #ifndef SCM_MATH_CORRECT_BIN_OPS return (vec<scal_type, 4>(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w)); #else vec<scal_type, 4> tmp(lhs); tmp += rhs; return (tmp); #endif }Bei meinen Messungen ist die direkte Variante fast doppelt so schnell wie die Variante mit der temporären Variablen (MS VC und GCC). Gibt es einen Weg dem Compiler hier noch auf die Sprünge zu helfen ohne Optimierungen wie von Blinn beschrieben zu verwenden?
-
Compilierst du im DEBUG mode oder im release-mode? eventuell hat das Einfluss darauf, ob der Compiler die NRVO überhaupt verwendet.
-
Im Release mit /O2 (MS) und /O3 (gcc).