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;
    
    #endif
    

    leider 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 externals
    

    Vielen Dank für jede Hilfe! Niko



  • EDIT: Ich nehme das zurück. War oberflächlich gelesen und Quatsch.

    Gruß,

    Simon2.


  • Mod

    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!


Anmelden zum Antworten