template vektor klasse und template funktionen
-
So, ich schreibe im Moment zu lernzwecken eine eigene Vektor-Klasse (Vektor als der mathematishen Vektor, nicht als Container).
Da ich ein Problem gerne ein für alle mal löse, dachte ich mir, mach ich ein template für einen n-Dimensionalen Vektor welcher als zusätzliches template-Argument den Typ, welcher zur Speicherung der n Koordinaten benutzt wird, erhält (double, int, float etc.).
Leider treten hierbei Fehler auf, welche ich mir nicht erklären kann (ich habe noch nicht so viel mit templates gearbeitet).Hier mein Code:
#if !defined(VECTOR2D_INCLUDED) #define VECTOR2D_INCLUDED #if _MSC_VER > 1000 #pragma once #endif #include "Math.hpp" //#include <cstdio>//?? //#include <cstdlib>//?? #include <cstdarg> template<class T, int Dimension> class Vector { private: T Scalars[Dimension]; protected: public: T GetLength() const { return sqrt(DotProduct(*this,*this)); } T GetScalar(int dimension) const { if (dimension<Dimension) { return Scalars[dimension]; } else { throw("bereichsüberschreitung vector getscalar"); } } void SetLength(T length) { (*this)*=(length/this->GetLength()) } void Normalize() { this->SetLength(1); } Vector(const Vector<T, Dimension>& vector) { for (int i = 0; i<Dimension;i++) { this->Scalars[i]=vector.Scalars[i]; } } Vector() { for (int i = 0;i<Dimension;++i) { Scalars[i] = 0; } } Vector(T scalar, ...) { Scalars[0] = scalar; va_list zeiger; va_start(zeiger,scalar); for (int i = 0;i+1<Dimension;++i) { Scalars[i+1] = va_arg(zeiger,int); } } virtual ~Vector() { } Vector& operator= (const Vector& vector) { for (int i = 0, i<Dimension;i++) { this->Scalars[i]=vector.Scalars[i]; } } void operator+= (const Vector& vector) //?????????void??? { for (int i = 0, i<Dimension;i++) { this->Scalars[i]+=vector.Scalars[i]; } } void operator-= (const Vector& vector) { for (int i = 0, i<Dimension;i++) { this->Scalars[i]-=vector.Scalars[i]; } } void operator*= (const T& scalar) { for (int i = 0, i<Dimension;i++) { this->Scalars[i]*=vector.Scalars[i]; } } void operator/= (const T& scalar) { if (scalar==0) { throw("also, für Koordinaten geht das nicht, für numerische typen geht das nicht, warum sollte das mit nem vektor gehen? nen unendlich langer vektor? nene, der passt doch nicht auf den Schirm!"); } else { for (int i = 0; i<Dimension;i++) { this->Scalars[i]/=scalar; } } } Vector<T, Dimension> operator/ (const T& right) const { Vector<T,Dimension> temp; if (right == 0) { throw("äh nö, auch mit dem Operator gehts gaz dick in die Hose!!!! (aiaiai, dassollte wer aufwischen und zwar schnell!!!!!!"); } else { for(int i = 0;i<Dimension;i++) { temp.Scalars[i]=this->Scalars[i]/right; } } return temp; } Vector<T, Dimension> operator* (const T& right) const { Vector<T,Dimension> temp; for(int i = 0;i<Dimension;i++) { temp.Scalars[i]=this->Scalars[i]*right; } return temp; } Vector<T, Dimension> operator+ (const Vector<T, Dimension>& right) { Vector<T,Dimension> temp; for(int i = 0;i<Dimension;i++) { temp.Scalars[i]=this->Scalars[i]+right.Scalars[i]; } return temp; } Vector<T, Dimension> operator- (const Vector<T, Dimension>& right) { Vector<T,Dimension> temp; for(int i = 0;i<Dimension;i++) { temp.Scalars[i]=this->Scalars[i]-right.Scalars[i]; } return temp; } /*friend Vector<T, Dimension> operator- (const Vector<T, Dimension>& left, const Vector<T, Dimension>& right); friend Vector<T, Dimension> operator+ (const Vector<T, Dimension>& left, const Vector<T, Dimension>& right); */ friend T DotProduct(const Vector<T, Dimension>& left, const Vector<T, Dimension>& right); }; /*template <class T, int Dimension> Vector<T, Dimension> operator+ (const Vector<T, Dimension>& left, const Vector<T, Dimension>& right) { Vector<T,Dimension> temp; for(int i = 0;i<Dimension;i++) { temp.Scalars[i]=left.Scalars[i]+right.Scalars[i]; } return temp; } template <class T, int Dimension> Vector<T, Dimension> operator- (const Vector<T, Dimension>& left, const Vector<T, Dimension>& right) { Vector<T,Dimension> temp; for(int i = 0;i<Dimension;i++) { temp.Scalars[i]=left.Scalars[i]-right.Scalars[i]; } return temp; } */ template <class T, int Dimension> T DotProduct(const Vector<T, Dimension>& left, const Vector<T, Dimension>& right) { T result = 0; for(int i = 0;i<Dimension;i++) { result += left.Scalars[i]*right.Scalars[i]; } return result; } typedef Vector<double,2> Vector2DDouble; #endifleider ergibt folgende Verwendung:
Vector<double,2> centre; double a = DotProduct<double,2>(centre,centre);folgende Fehlermeldung:
\vector.hpp(213) : error C2248: 'Vector<T,Dimension>::Scalars' : cannot access private member declared in class 'Vector<T,Dimension>' with [ T=double, Dimension=2 ] \vector.hpp(17) : see declaration of 'Vector<T,Dimension>::Scalars' with [ T=double, Dimension=2 ] \somevectorusingclass.cpp(71) : see reference to function template instantiation 'T DotProduct<double,2>(const Vector<T,Dimension> &,const Vector<T,Dimension> &)' being compiled with [ T=double, Dimension=2 ] \vector.hpp(213) : error C2248: 'Vector<T,Dimension>::Scalars' : cannot access private member declared in class 'Vector<T,Dimension>' with [ T=double, Dimension=2 ] \vector.hpp(17) : see declaration of 'Vector<T,Dimension>::Scalars' with [ T=double, Dimension=2 ]Hab ich mit der friend-deklaration etwas falsch gemacht? Oder habe ich einen kompletten Dekfehler?
Außerdem, warum muss ich beim Aufruf von DotProdukt
double a = DotProduct<double,2>(centre,centre)und nicht nur
double a = DotProduct(centre,centre)schreiben?
(wenn ich es nicht tue, ergibt sich folgender Linker-Fehler:
somevectorusingclass.obj : error LNK2019: unresolved external symbol "double __cdecl DotProduct(class Vector<double,2> const &,class Vector<double,2> const &)" (?DotProduct@@YANABV?$Vector@N$01@@0@Z) referenced in function "public: virtual void __thiscall somevectorusingclass::Draw(int,int,int,int,double,double,double)" (?Draw@somevectorusingclass@@UAEXHHHHNNN@Z) .exe : fatal error LNK1120: 1 unresolved externalsVielen Dank für jede Hilfe! Niko
-
EDIT: Ich nehme das zurück. War oberflächlich gelesen und Quatsch.
Gruß,
Simon2.
-
durch
friend T DotProduct(const Vector<T, Dimension>& left, const Vector<T, Dimension>& right);deklarierst du eine funktion DotProduct, die keine templatefunktion ist. solange diese funktion nicht redeklariert wird, ist sie zwar nicht durch normales lookup, wohl aber durch Koenig-lookup in einem funktionsaufruf auffindbar. und genau das passiert in:
DotProduct(centre,centre)DotProduct<double,2> wäre für diesen ausdruck gleichgut - in diesen fällen wird aber die funktion, die keine templatefunktion ist, vorgezogen. die overload-auflösung entscheidet sich also für die funktion, die in der friend-deklaration deklariert wird - und in folge kommt es dann zu einem linker-fehler, denn besagte funktion wird nie definiert.
was du willst, ist wohl, entweder das template DotProdukt
template<class T, int Dimension> class Vector { // ... template <class, int> friend T DotProduct(const Vector<T, Dimension>& left, const Vector<T, Dimension>& right); };oder nur eine bestimmte instanz davon (diejenige mit übereinstimmenden templateargumenten) als friend zu deklarieren. da sich letzteres allerdings auf eine spezialisierung bezieht, muss das primärtemplate vorher deklariert werden.
template<class T, int Dimension> class Vector; template <class T, int Dimension> T DotProduct(const Vector<T, Dimension>& left, const Vector<T, Dimension>& right); template<class T, int Dimension> class Vector { // ... friend T DotProduct<T, Dimension>(const Vector<T, Dimension>& left, const Vector<T, Dimension>& right); };
-
Dabke camper, für die schnelle antwort, ja, die 2. Variante war es, die ich brauche.
P.s.: Hast du den Beitrag gerade editiert? Die war doch eben anders, da gab das ne Fehlermeldung, das wollt ich gerade tippen, aber so wies jetzt da steht funzts wunderbar, danke!