Problem mit meiner Template Klasse



  • Sehr geehrte Community,

    ich versuche grad eine Gridtemplateklasse zu machen, die eine Triggerfunktion hat, falls sich der Inhalt ändert.

    es besteht aus 3 Template klassen

    type<T> ist der typ, welcher als Value T aufnimmt und bei veränderung die Funktion hinter dem Pointer void *func steht.

    aufruf wird so gemacht

    (*this->func)(this); <-- Gibt zur Funktion ein Pointer von sich selbst ab.

    row<T> sind die rows und vererbt std::map<unsigned int,type<T>>

    dieser hat auch eine Trigger Funktion und einen Funktionspointer.

    die Triggerfunktion wird ausgelöst, wenn type<T> inhalt geändert wird und ruft die Funktion, auf die der funktionspointer zeigt.

    (*this->trigger)(this,i); also auf sich selbst ein Zeiger und den Zeiger auf type.

    letzte Template Klasse ist Grid<T>, die std::map<unsigned int,row<T>> vererbt.

    Die hat ebenfalls eine Triggerfunktion und einen Funktionspointer
    die Triggerfunkion übernimmt die beiden pointer und übergibt den pointer von sich selbst und von row, damit der verarbeitende Funktion weiß wo und welche Daten verändert worden sind.

    container.hpp

    #ifndef _CONTAINER_HPP
    #define _CONTAINER_HPP
    
    #include<map>
    #include<iterator>
    #include<memory>
    #include<typeinfo>
    
    #define me (*this)
    
    #define destroymap std::map<std::string,void (*)()>
    
    namespace WINAPIpp
    {
    	namespace TEMPLATES
    	{
    		template<class T, class U, class V>
    		class Triplet
    		{
    		private:
    			T first;
    			U second;
    			V third;
    			destroymap destroy;
    		protected:
    		public:
    			Triplet(T, U, V);
    			Triplet(T * (*f1)(), U *(*f2)(), V *(*f3)());
    			~Triplet();
    			std::shared_ptr<T> getFirst();
    			std::shared_ptr<U> getSecond();
    			std::shared_ptr<V> getThird();
    		};
    
    		template<class T>
    		class type
    		{
    		private:
    			T data;
    			void* func;
    		protected:
    		public:
    			type(void(*trigger)(type<T>*));
    			~type(){ delete this->func; }
    
    			//void the type;
    
    			//operator overloading
    			T& operator=(const T& rhs);
    			T& operator++(int);
    			T operator+(T& rhs);
    			T& operator--(int rhs);
    			T operator-(T& rhs);
    			//T& operator+=(const T& rhs);
    			//T& operator-=(const T& rhs);
    			//T& operator*=(const T& rhs);
    			//T& operator/=(const T& rhs);
    			T operator*(const T& rhs);
    			T operator/(const T& rhs);
    		};
    
    		template<class T>
    		class row : public std::map<unsigned int, type<T>>
    		{
    		public:
    			row(void(*trigger)(row<T>*));
    			//row(T, void(*trigger)(row<T>*));
    			~row(){}
    			void insert(T);
    		protected:
    			//void append_rows(unsigned int n);
    			//void delete_row(unsigned int,bool = true);
    			void append_trigger(void(*trigger)(row<T>*));
    			void trigger_func(type<T>* ptr);
    		private:
    			void* trigger;
    		};
    
    		template<class T>
    		class Grid : public std::map<unsigned int, row<T>>
    		{
    		private:
    			void* trigger;
    		protected:
    			void trigger_func(row<T>*);
    		public:
    			Grid(void(*mytrigger)(Grid<T>*, row<T>*));
    			//Grid(T);
    			~Grid(){}
    			void append_trigger( void(*f)(Grid<T>*,row<T>*));
    
    		};
    	}
    }
    
    #endif
    

    container.cpp

    #include"container.hpp"
    #include<type_traits>
    
    using namespace WINAPIpp::TEMPLATES;
    
    //TYPE
    
    template<class T>
    type<T>::type(void(*trigger)(type<T> *))
    {
    	this->func = trigger;
    }
    
    template<class T>
    T& type<T>::operator=(const T& rhs)
    {
    	this->data = rhs;
    	if (this->func != NULL)
    		(*this->func)(this);
    	return this;
    }
    
    template<class T>
    T& type<T>::operator++(int rhs)
    {
    	this->data = this->data + (T)rhs;
    	if (this->func != NULL)
    		(*this->func)(this);
    	return rhs;
    }
    
    template<class T>
    T type<T>::operator+(T& rhs)
    {
    	T tmp = this->data + rhs.data;
    	return tmp;
    }
    
    template<class T>
    T& type<T>::operator--(int rhs)
    {
    	this->data = this->data - (T)rhs;
    	if (this->func != NULL)
    		(*this->func)(this);
    	return this;
    }
    
    template<class T>
    T type<T>::operator-(T& rhs)
    {
    	T tmp = this->data - rhs.data;
    
    	return this;
    }
    
    template<class T>
    T type<T>::operator*(const T& rhs)
    {
    	T tmp = this->data * rhs.data;
    	return tmp;
    }
    
    template<class T>
    T type<T>::operator/(const T& rhs)
    {
    	T tmp = this->data / rhs.data;
    	return tmp;
    }
    
    //row
    
    template<class T>
    void row<T>::trigger_func(type<T>* ptr)
    {
    	row<T>::iterator iter(ptr);
    	(*this->trigger)(&(*iter));
    }
    
    template<class T>
    row<T>::row(void(*trigger)(row<T>*))
    {
    	this->trigger = trigger;
    }
    
    template<class T>
    void row<T>::insert(T value)
    {
    	if (this->size() != 0)
    	{
    		type<T> tmp(&row<T>::trigger_func);
    		tmp = value;
    		me[(this->rbegin()->first + 1)] = T;
    	}
    	else
    	{
    		type<T> tmp(&row<T>::trigger_func);
    		me[0] = tmp;
    	}
    }
    
    template<class T>
    void row<T>::append_trigger(void(*trigger)(row<T>*))
    {
    	me.trigger = trigger;
    }
    
    //grid
    
    template<class T>
    void Grid<T>::trigger_func(row<T>* iter)
    {
    	Grid<T>::iterator i(iter);
    	(*this->trigger)(&(*i),iter);
    }
    
    template<class T>
    Grid<T>::Grid(void(*mytrigger)(Grid<T>*, row<T>*))
    {
    	me.trigger = mytrigger;
    }
    
    template<class T>
    void Grid<T>::append_trigger(void(*f)(Grid<T>*, row<T>*))
    {
    	me.trigger = f;
    }
    
    //TRIPLET
    template<class T, class U, class V>
    Triplet<T,U,V>::~Triplet()
    {
    	if (this->destroy.find(typeid(T)) != this->destroy.end())
    	{
    		this->destroy[typeid(T)]();
    	}
    	else
    	{
    		if (std::is_pointer<T>::value)
    			delete this->first;
    		else
    			delete &this->first;
    	}
    	if (this->destroy.find(typeid(U)) != this->destroy.end())
    	{
    		this->destroy[typeid(U)]();
    	}
    	else
    	{
    		if (std::is_pointer<U>::value)
    			delete this->second;
    		else
    			delete &this->second;
    	}
    	if (this->destroy.find(typeid(V)) != this->destroy.end())
    		this->destroy[typeid(V)]();
    	else
    	{
    		if (std::is_pointer<V>::value)
    			delete this->third;
    		else
    			delete &this->third;
    	}
    }
    
    template<class T,class U,class V>
    std::shared_ptr<T> Triplet<T, U, V>::getFirst()
    {
    	return std::shared_ptr<T>(this->first);
    }
    
    template<class T, class U, class V>
    std::shared_ptr<U> Triplet<T, U, V>::getSecond()
    {
    	return std::shared_ptr<U>(this->second);
    }
    
    template<class T, class U, class V>
    std::shared_ptr<V> Triplet<T, U, V>::getThird()
    {
    	return std::shared_ptr<V>(this->Third);
    }
    

    Quelle.cpp (beinhaltet die main)

    #include"container.hpp"
    #include<iostream>
    using namespace WINAPIpp::TEMPLATES;
    
    void trigger(Grid<int>*, row<int>*);
    
    int main()
    {
    	Grid<int> test(&trigger);
    }
    
    void trigger(Grid<int>* p, row<int>* x)
    {
    	std::cout << "Triggered" << std::endl;
    }
    

    Der Namespace WINAPIpp und TEMPLATES habe ich gewählt, weil das hier ein Teil eines größeren Projektes sein wird.

    Es ist auch nicht fertig. Wollte eigentlich nur mal testen, ob es läuft. Aber es kommt ein Linker Error, weiß nur nicht, wo der Fehler ist.

    `Fehler 1 error LNK2019: Verweis auf nicht aufgelöstes externes Symbol ""public: __thiscall WINAPIpp::TEMPLATES::Grid<int>::Grid<int>(void (__cdecl*)(class WINAPIpp::TEMPLATES::Grid<int> *,class WINAPIpp::TEMPLATES::row<int> *))" (??0?Grid@H@TEMPLATES@WINAPIpp@@QAE@P6AXPAV012@PAV?Grid@H@TEMPLATES@WINAPIpp@@QAE@P6AXPAV012@PAV?row@H@12@@Z@Z)" in Funktion "_main". C:\Users\Platz1300\documents\visual studio 2013\Projects\container\container\Quelle.obj container

    `

    Ich schätze mal, es gibt ein Prototyp, der keine Definition hat, sehe aber nicht welche Funktion es sein soll. Laut VS2013 soll der Konstruktor von Grid<T> eine Überladung haben 😮

    Danke für die Hilfe

    Mit freundlichen Grüßen
    Sepultura



  • Der Namespace WINAPIpp und TEMPLATES habe ich gewählt, weil das hier ein Teil eines größeren Projektes sein wird

    Normalerweise wird das Modul nicht nach den benutzen Techniken benannt.

    Weiterhin muss die Definition eines Templates ueberall dort bekannt sein, wo sie auch genutzt wird. Im einfachsten Fall erreicht man das, indem Deklaration und Definition sich in der gleichen Headerdatei befinden, d.h. Inhalt von container.cpp in container.h packen.



  • aber außerhalb der class Grid{} dürfen die Funktionen sein? Also ich würde sie ganz unten anhängen.

    Die Namespaces habe ich so gewählt:

    WINAPIpp <- Mein Projekt, ein Wrapper für WINAPI

    Es gibt schon:

    WINAPIpp::Registry Namespace
    die Registry Operationen macht

    WINAPIpp::PROCESS Namespace
    mit Klassen
    ProcessContainer
    Process

    für laufende Laufende Processe

    und die TEMPLATES Namespace sind halt für zusätzliche Klassen da. Da ProcessContainer einen Trigger braucht, habe ich diese Klassen zur erlernung davon gestartet.

    Mit freundlichen Grüßen
    Sepultura



  • Es heißt nicht "Template Klasse". Das macht doch keinen Sinn! Übersetz das mal: "Schablonenklasse"? Nee! "Klassenschablone"? Ja. --> Klassen-Template

    Die Fehlermeldung vom Linker siehst Du deswegen, weil Du sehr wahrscheinlich die ODR (one-definition-rule) nicht beachtet hast. Bin da jetzt nur drüber geflogen, aber man sieht sofort, dass das meiste wenn nicht alles aus container.cpp da nicht hingehört.

    Siehe
    http://www.linuxtopia.org/online_books/programming_books/c++_practical_programming/c++_practical_programming_134.html

    Und siehe:
    ODR (in einem C++ Buch Deiner Wahl)



  • Hallo, hier die bessere Edition:

    container.hpp

    #ifndef _CONTAINER_HPP
    #define _CONTAINER_HPP
    
    #include<map>
    #include<iterator>
    #include<memory>
    #include<typeinfo>
    
    #define me (*this)
    
    #define destroymap std::map<std::string,void (*)()>
    
    namespace WINAPIpp
    {
    	namespace TEMPLATES
    	{
    		template<class T, class U, class V>
    		class Triplet
    		{
    		private:
    			T first;
    			U second;
    			V third;
    			destroymap destroy;
    		protected:
    		public:
    			Triplet(T, U, V);
    			Triplet(T * (*f1)(), U *(*f2)(), V *(*f3)());
    			~Triplet();
    			std::shared_ptr<T> getFirst();
    			std::shared_ptr<U> getSecond();
    			std::shared_ptr<V> getThird();
    		};
    
    		template<class T>
    		class type
    		{
    		private:
    			T data;
    			void* func;
    		protected:
    		public:
    			type(void(*trigger)(type<T>*));
    			~type(){ delete this->func; }
    
    			//void the type;
    
    			//operator overloading
    			T& operator=(T& rhs);
    			T& operator++(int);
    			T operator+(T& rhs);
    			T& operator--(int rhs);
    			T operator-(T& rhs);
    			//T& operator+=(const T& rhs);
    			//T& operator-=(const T& rhs);
    			//T& operator*=(const T& rhs);
    			//T& operator/=(const T& rhs);
    			T operator*(const T& rhs);
    			T operator/(const T& rhs);
    		};
    
    		template<class T>
    		class row : public std::map<unsigned int, type<T>>
    		{
    		public:
    			row(void(*trigger)(row<T>*));
    			//row(T, void(*trigger)(row<T>*));
    			~row(){}
    			void insert(T);
    		protected:
    			//void append_rows(unsigned int n);
    			//void delete_row(unsigned int,bool = true);
    			void append_trigger(void(*trigger)(row<T>*));
    			void trigger_func(type<T>* ptr);
    		private:
    			void* trigger;
    		};
    
    		template<class T>
    		class Grid : public std::map<unsigned int, row<T>>
    		{
    		private:
    			void* trigger;
    		protected:
    			void trigger_func(row<T>*);
    		public:
    			Grid(void(*mytrigger)(Grid<T>*, row<T>*));
    			//Grid(T);
    			~Grid(){}
    			void append_trigger(void(*f)(Grid<T>*, row<T>*));
    			void insert(T);
    
    		};
    
    		template<class T>
    		type<T>::type(void(*trigger)(type<T> *))
    		{
    			this->func = trigger;
    		}
    
    		template<class T>
    		T& type<T>::operator=(T& rhs)
    		{
    			this->data = rhs;
    			if (this->func != NULL)
    				(*this->func)(this);
    			return this;
    		}
    
    		template<class T>
    		T& type<T>::operator++(int rhs)
    		{
    			this->data = this->data + (T)rhs;
    			if (this->func != NULL)
    				(*this->func)(this);
    			return rhs;
    		}
    
    		template<class T>
    		T type<T>::operator+(T& rhs)
    		{
    			T tmp = this->data + rhs.data;
    			return tmp;
    		}
    
    		template<class T>
    		T& type<T>::operator--(int rhs)
    		{
    			this->data = this->data - (T)rhs;
    			if (this->func != NULL)
    				(*this->func)(this);
    			return this;
    		}
    
    		template<class T>
    		T type<T>::operator-(T& rhs)
    		{
    			T tmp = this->data - rhs.data;
    
    			return this;
    		}
    
    		template<class T>
    		T type<T>::operator*(const T& rhs)
    		{
    			T tmp = this->data * rhs.data;
    			return tmp;
    		}
    
    		template<class T>
    		T type<T>::operator/(const T& rhs)
    		{
    			T tmp = this->data / rhs.data;
    			return tmp;
    		}
    
    		//row
    
    		template<class T>
    		void row<T>::trigger_func(type<T>* ptr)
    		{
    			row<T>::iterator iter(ptr);
    			(*this->trigger)(&(*iter));
    		}
    
    		template<class T>
    		row<T>::row(void(*trigger)(row<T>*))
    		{
    			this->trigger = trigger;
    		}
    
    		template<class T>
    		void row<T>::insert(T value)
    		{
    			if (this->size() != 0)
    			{
    				type<T> tmp(&row<T>::trigger_func);
    				tmp = value;
    				me[(this->rbegin()->first + 1)] = value;
    			}
    			else
    			{
    				type<T> tmp(&row<T>::trigger_func);
    				me[0] = tmp;
    			}
    		}
    
    		template<class T>
    		void row<T>::append_trigger(void(*trigger)(row<T>*))
    		{
    			me.trigger = trigger;
    		}
    
    		//grid
    
    		template<class T>
    		void Grid<T>::trigger_func(row<T>* iter)
    		{
    			Grid<T>::iterator i(iter);
    			(*this->trigger)(&(*i), iter);
    		}
    
    		template<class T>
    		Grid<T>::Grid(void(*mytrigger)(Grid<T>*, row<T>*))
    		{
    			me.trigger = mytrigger;
    		}
    
    		template<class T>
    		void Grid<T>::append_trigger(void(*f)(Grid<T>*, row<T>*))
    		{
    			me.trigger = f;
    		}
    
    		template<class T>
    		void Grid<T>::insert(T value)
    		{
    			if (this->size() == 0)
    				me[0].insert(value);
    			else
    				me[me.rbegin()->first + 1].insert(value);
    		}
    
    		//TRIPLET
    		template<class T, class U, class V>
    		Triplet<T, U, V>::~Triplet()
    		{
    			if (this->destroy.find(typeid(T)) != this->destroy.end())
    			{
    				this->destroy[typeid(T)]();
    			}
    			else
    			{
    				if (std::is_pointer<T>::value)
    					delete this->first;
    				else
    					delete &this->first;
    			}
    			if (this->destroy.find(typeid(U)) != this->destroy.end())
    			{
    				this->destroy[typeid(U)]();
    			}
    			else
    			{
    				if (std::is_pointer<U>::value)
    					delete this->second;
    				else
    					delete &this->second;
    			}
    			if (this->destroy.find(typeid(V)) != this->destroy.end())
    				this->destroy[typeid(V)]();
    			else
    			{
    				if (std::is_pointer<V>::value)
    					delete this->third;
    				else
    					delete &this->third;
    			}
    		}
    
    		template<class T, class U, class V>
    		std::shared_ptr<T> Triplet<T, U, V>::getFirst()
    		{
    			return std::shared_ptr<T>(this->first);
    		}
    
    		template<class T, class U, class V>
    		std::shared_ptr<U> Triplet<T, U, V>::getSecond()
    		{
    			return std::shared_ptr<U>(this->second);
    		}
    
    		template<class T, class U, class V>
    		std::shared_ptr<V> Triplet<T, U, V>::getThird()
    		{
    			return std::shared_ptr<V>(this->Third);
    		}
    	}
    }
    
    #endif
    

    Quelle.cpp

    #include"container.hpp"
    #include<iostream>
    using namespace WINAPIpp::TEMPLATES;
    
    void trigger(Grid<int>*, row<int>*);
    
    int main()
    {
    	Grid<int> test(&trigger);
    	test.insert(10);
    	system("pause");
    	return 0;
    }
    
    void trigger(Grid<int>* p, row<int>* x)
    {
    	std::cout << "Triggered" << std::endl;
    }
    

    jetzt meckert er bei Zeile 178 und 184.

    type<T> tmp(&row<T>::trigger_func);
    
    type<T> tmp(&row<T>::trigger_func);
    

    mit den Fehlern:

    `Fehler 1 error C2664: 'WINAPIpp::TEMPLATES::type<T>::type(const WINAPIpp::TEMPLATES::type<T> &)' : Konvertierung von Argument 1 von 'void (__thiscall WINAPIpp::TEMPLATES::row<int>::* )(WINAPIpp::TEMPLATES::type<T> *)' in 'void (__cdecl *)(WINAPIpp::TEMPLATES::type<T> *)' nicht möglich c:\users\owner\documents\visual studio 2013\projects\template\template\container.hpp 178 1 TEMPLATE

    `

    und

    `Fehler 2 error C2664: 'WINAPIpp::TEMPLATES::type<T>::type(const WINAPIpp::TEMPLATES::type<T> &)' : Konvertierung von Argument 1 von 'void (__thiscall WINAPIpp::TEMPLATES::row<int>::* )(WINAPIpp::TEMPLATES::type<T> *)' in 'void (__cdecl *)(WINAPIpp::TEMPLATES::type<T> *)' nicht möglich c:\users\owner\documents\visual studio 2013\projects\template\template\container.hpp 184 1 TEMPLATE

    `

    Was ist an den Trigger Funktionen bzw. deren Pointern falsch?

    Mit freundlichen Grüßen



  • Du kannst keinen Memberfunktionspointer in einen normalen Funktionspointer konvertieren.



  • Irgendwelche Lösung?



  • std::function + bind/lambda
    template parameter + bind/lambda/functor



  • meinst du sowas?
    std::function<void(type<T>*)> f = std::bind(&row<T>::trigger_func);

    http://de.cppreference.com/w/cpp/utility/functional/function
    http://www.cplusplus.com/reference/functional/bind/



  • Ja, musst nur noch einen Pointer to row<T> an trigger_func binden, sonst bringt das nichts:

    T *obj;
    MemberFncPtr fnc = &T::function;
    obj->fnc(...);
    // daraus wird analog:
    T *obj;
    std::function<ReturnType(Args...)> fnc = std::bind(&T::function, obj);
    fnc(...);
    


  • Vielen Dank 🙂

    Es ist aber spät. Ich werde morgen den Code weiter bearbeiten.


Log in to reply