Template Spezialisierung



  • Hi, ich habe folgendes Problem:
    Ich habe eine Klasse Vektor, mit den Methoden Add, operator+, Subtract, ... .
    Diese Klasse ist ein Template, so das man n-dimensional Vektoren erzeugen kann (Vektor<n> x)
    Jetzt möchte ich aber für 3-Dimensional Vektoren eine bestimmte Methode haben, aber die anderen Methoden beibehalten. Ich habe es schon mit

    //Vektor Klasse algemein
    template <int n>
    class Vektor {
    //... Add(), Subtract(), ...
    };
    
    //Vektor Klasse spezialisiert
    template <>
    class Vektor<3> {
    //... X(), Y(), Z(), ...
    }
    

    probiert, aber dann gehen die Methoden Subtract, Add, ... , die ich nur in dem allgemeinem Vektor definiert habe verloren. Ich möchte aber nicht nochmal das selbe für 3-Dimensionale Vektoren schreiben, sondern nur ein paar Methoden hinzufügen, die alten aber beibehalten.

    Ich hoffe das war Verständlich 😕



  • hola

    vielleicht so:

    //Vektor Klasse algemein
    template <int n>
    class Vektor {
    //... Add(), Subtract(), ...
       ret_value nur_fuer_3(param p);
    };
    
    /* ausserhalb der klasse */
    template<>
    ret_value Vector<3>::nur_fuer_3(param p)
    {
       mach_was();
    }
    

  • Mod

    Lösung 1: Gemeinsame Funktionalität in Basisklasse auslagern. Allgemeines Template und spezialisiertes Template erben von dieser.
    Lösung 2: Vielleicht tun ja auch freie Funktionen das was du möchtest. So etwas wie Kreuzprodukt ist beispielsweise eher als freie Operation auf Vektoren der Länge 3 anzusehen, anstatt einer Funktion die ein Vektor mit sich selbst durchführt.



  • Ich hatte das gleiche Problem und leider habe ich als Lösung nur Vererbung gefunden. (Ging konkret um einen Konstruktor.)
    Wäre mit variadic Templates vielleicht sogar anders möglich, aber solange MS das nicht unterstützt.. 😞



  • Ich bin grade etwas ratlos, um ehrlich zu sein. Folgende Ansätze hätte ich:

    1. Deklariere die Methoden im allgemeinen Template, implementiere sie nur für Vector<3> (so wie MeepMeep, allerdings mit SFINAE gewürzt)
    //Vektor Klasse algemein
    template <int n>
    class Vektor {
    //... Add(), Subtract(), ...
       template <class = enable_if<n==3, void>::type>
       void nur_fuer_3(param p);
    };
    
    /* ausserhalb der klasse */
    template<>
    template<>
    void Vector<3>::nur_fuer_3<void>(param p)
    {
       /* ... */;
    }
    
    1. Verlagere die gemeinsamen Dinge in ein Basisklassentemplate:
    template <int N>
    struct VektorImpl
    {
    //... Add(), Subtract(), ...
    };
    
    template <int N>
    class Vektor : VektorImpl<N>
    {};
    
    template <>
    class Vektor<3> : VektorImpl<3>
    {
      void nur_fuer_3(param p) {/* ... */};
    };
    

    (Ohne Gewähr, ungetestet)


  • Mod

    cooky451 schrieb:

    Ich hatte das gleiche Problem und leider habe ich als Lösung nur Vererbung gefunden. (Ging konkret um einen Konstruktor.)

    Das ist philosophisch aber durchaus richtig. Eine Spezialisierung beschreibt eine andere Umsetzung, Vererbung beschreibt eine Erweiterung. Hier soll Funktionalität hinzu gefügt werden.



  • Das mit der Basis Klasse habe ich schon probiert. Problem:
    Ich möchte ja in Subtract, Add, ... einen Vektor und keinen VektorBase zurückgeben. Wenn ich aber dann schreibe

    template <unsigned int n>
    Vektor& VektorBase<n>::operator/=(float x) {
    // ...
    return *this;
    }
    

    geht das ja nicht ...

    Das mit den freien Methoden ist mir auch eingefallen nachdem ich den Thread geöffnet hatte, werde ich mal probieren 🙂 Dann sollte das ja ganze einfach sein

    Meinst du mit Veerbung sowas wie Vektor -> Vektor3D ? Ist aber schöner wenn man Vektor<3> anstelle von Vektor3D schreiben kann und trotzdem die speziellen Methoden bekommt 🙂



  • Die allgemeinen Methoden des Vektors kann man schön generisch implementieren.
    Statt Spezialisierung würde ich lieber eine freie Funktion nehmen.

    #include <boost/array.hpp>
    #include <boost/static_assert.hpp>
    
    template <class E, size_t N>
    struct vector
    {
    	boost::array<E, N> elements;
    
    	void add(const vector &other)
    	{
    		for (size_t i = 0; i < N; ++i)
    		{
    			elements[i] += other.elements[i];
    		}
    	}
    };
    
    template <size_t Index>
    struct accessor
    {
    	template <class E, size_t N>
    	E &operator()(vector<E, N> &v)
    	{
    		BOOST_STATIC_ASSERT(Index < N);
    		return v.elements[Index];
    	}
    };
    
    static accessor<0> x;
    static accessor<1> y;
    static accessor<2> z;
    
    template <class E>
    void super_special_method(vector<E, 3> &v)
    {
    }
    
    int main()
    {
    	vector<double, 3> v;
    	x(v) = 12;
    	y(v) = 6;
    	z(v) = 3;
    
    	super_special_method(v);
    }
    


  • pyhax schrieb:

    Das mit der Basis Klasse habe ich schon probiert. Problem:
    Ich möchte ja in Subtract, Add, ... einen Vektor und keinen VektorBase zurückgeben. Wenn ich aber dann schreibe

    template <unsigned int n>
    Vektor& VektorBase<n>::operator/=(float x) {
    // ...
    return *this;
    }
    

    geht das ja nicht ...

    Vererben, dazu ein paar freie Funktionen. Funktioniert schon.
    Aber naja, ich habe seit Jahren kein C++ mehr programmiert ... hoffe mal es ist nicht zu katastrophal 😉

    #include <iostream>
    //using namespace std;
    
    #ifndef VECTORN_H
    #define VECTORN_H
    
    namespace Mathematics
    {
    	template<typename T, int N>
    		class Vector;
    
    	template<typename T, int N>
    		class VectorBase
    		{
    			protected:
    				T data[N];
    
    				VectorBase()
    				: data()
    				{}
    
    			public:
    				T Sum() const;
    				T& operator[](int index);
    				const T& operator[](int index) const;
    
    				template<typename T, int N>
    				friend Vector<T,N>& operator+=(Vector<T,N>& a, Vector<T,N> const& b);
    		};
    
    	template<typename T, int N>
    		T VectorBase<T,N>::Sum() const
    		{
    			T sum = 0;
    			for(int i=0; i<N; ++i)
    				sum+=data[i];
    
    			return sum;
    		}
    
    	template<typename T, int N>
    		T& VectorBase<T,N>::operator[](int index)
    		{
    			return data[index];
    		}
    
    	template<typename T, int N>
    		const T& VectorBase<T,N>::operator[](int index) const
    		{
    			return data[index];
    		}
    
    	template<typename T, int N>
    		std::ostream& operator<<(std::ostream& out, VectorBase<T,N> const& vec)
    		{
    			out<<"(";
    			for(int i=0;i<N;++i)
    				out<<vec[i]<<(i<N-1?",":")");
    			return out;
    		}
    
    	template<typename T, int N>
    		class Vector : public VectorBase<T,N>
    		{
    			public:
    				Vector()
    				{}
    		};
    
    	template<typename T>
    		class Vector<T,3> : public VectorBase<T,3>
    		{
    			public:
    				T& X;
    				T& Y;
    				T& Z;
    
    				Vector()
    					: X(this->data[0]), Y(this->data[1]), Z(this->data[2])
    				{}
    
    				Vector(T x, T y, T z)
    					: X(this->data[0] = x), Y(this->data[1] = y), Z(this->data[2] = z)
    				{}
    
    				static Vector<T,3> Cross(const Vector<T,3>& a, const Vector<T,3>& b)
    				{
    
    					return Vector (
    									a.Y*b.Z - a.Z*b.Y,
    									a.Z*b.X - a.X*b.Z,
    									a.X*b.Y - a.Y*b.X
      								  );
    				}
    		};
    
    	template<typename T, int N>
    		Vector<T,N>& operator+=(Vector<T,N>& a, Vector<T,N> const& b)
    		{
    			for(int i=0; i<N; ++i)
    				a.data[i]+=b.data[i];
    			return a;
    		}
    
    	template<typename T, int N>
    		const Vector<T,N> operator+(Vector<T,N> const& a, Vector<T,N> const& b)
    		{
    			Vector<T,N> tmp(a);
    			tmp+=b;
    			return tmp;
    		}
    }
    
    #endif // VECTORN_H
    

Anmelden zum Antworten