array als template



  • Hallo,

    ich weiß es gibt ein std::vector oder ähnliches. Im moment habe ich ein array welches nur mit pointern gefüllt ist und auf ein zweites array zeigt, bzw. die pointer innerhalb des ersten arrays zeigen sozusagen auf elemente des zweiten arrays. Eine art 2D array;

    double **arr1;
     double* arr2 = new double[];
    

    dieses soll jetzt je nach wahl mit doubles ODER mit einer struktur gefüllt werden.
    dazu wollte ich templates verwenden.

    ich wollte jetzt nicht was von der stl verwenden:
    Der Grund ist (auch wenn ich noch kein fortgeschrittener c++ programmierer bin) dass ich schon mal von der laufzeit her geringe laufzeiteinbussen deswegen gehabt habe. Habe damals alles ohne stl geschrieben und es war schneller...ich weiß dass viele jetzt denken: Das liegt an meinen kenntnissen aber gäbe es nicht die Möglichkeit ohne stl zu arbeiten?

    Ich finde allerdings überall nur versionen wo man eine ganze Klasse schreiben muss....geht das nicht einfacher?
    Ich befürchte wenn ich eine eigene array klasse schreibe wird die evlt. von der performance her nicht schneller sein...

    danke



  • Also wenn das Array eine konstante Größe hat, wäre boost::multi_array vielleicht einen Blick wert.



  • kurz gesagt: nein. Es gibt nur templates fuer Klassen oder Funktionen. Nun koennte man denken, dass du jetzt ein Funktions Template a la

    template <typename T>
    T* make_array(int length)
    {
      return new T[length];
    }
    

    schreiben kannst, aber das fuehrt dich nur zu dem Problem, dass du immernoch irgendwie die Typinformation rumschleifen musst. Das fuehrt dich kurz oder spaet zu einem eigenen Klassentemplate. Und das widerum wird mit ziemlicher Sicherheit langsamer sein als der fuer dein Problem angemessene STL Container.
    Du musst allerdings nicht unbedingt vector verwenden, es gibt ja auch noch list, deque und was weiss ich noch. Die Dinger unterscheiden sich vor allem durhc die geschwindigkeiten bei verschiedenen Arten des Zugriffs, beim Einfuegen und Loeschen etc. Es gibt Tabellen, bei welchem Container welche Operation besonders schnell geht, und du kannst deinen Container entsprechend den Beduerfnissen deines Programms dann auswaehlen.



  • danke -
    wieder was dazu gelernt.
    Ich greife auf die elemente des containers eigentlich öfters eher nacheinander von beginn zu. random access eher weniger...
    je schneller desto besser......ich fand bisher nur tabellen nur tabellen mit "konstant" und "linear" als laufzeit. aber da existieren bestimmt noch konstanten vor diesen bezeichnern - als detaillierter würde mich interessieren....gibt es da eine tabelle oder was würdet ihr raten?



  • wie könnte ich denn einen template std::vector erstellen:

    ich will das hier:

    double** arr;
    
    double* arr2;
    

    in einen template vector umsetzen:
    irgendwie so?

    std::vector<T*> arr;
    
    std::vector<T> arr2;
    


  • wenn du wirklich ein zweidimensionales array haben moechtest, nimm einfach einen
    std::vector< std::vector<double> >

    Ich meine mich allerdings erinnern zu koennen, dass man da nicht sofort anfangen kann, was einzutragen, sondern den aeusseren vector erst auf die richtige Groesse bringen muss und seine Elemente initialisieren.



  • Also sorry - ich muss nochmal erklären:

    ich habe eine Klasse:

    class Matrix
    {
          double **arr;
          double *arr2;
    };
    

    und in dieser Klasse will ich einen std::vector<T> so haben dass ich je nach belieben den vector füllen kann im nachhinein,

    das heißt wenn ich später dann zur laufzeit feststelle ich will Matrix->arr mit doubles füllen dann halt doubles ansonsten was anderes....

    leider geht das mit dem Template argument so nicht ....was muss ich dazu tun?



  • Oha. das ist was anderes und schon ein ganzes Stueck schwieriger.
    Das riecht fast danach, die Werte und alles was typspezifisch ist, in ein anderes Objekt auszulagern, das dann zur laufzeit gewechselt werden kann.

    class MatrixImpl {
      //abstrakte Basisklasse die eine typunabhaengige Schnittstelle der virtuellen Funktionen liefert, die von Matrix verwendet werden.
    public:
      virtual ~MatrixImpl() {} = 0;
    };
    
    class Matrix {
      MatrixImpl* impl;
    public:
      void loadImpl(MatrixImpl* newimpl) {delete impl; impl = newimpl;}
      //Methoden die nach aussen unabhaengig vom verwendeten Typ sind
    };
    
    template<typename T>
    class GenericMatrixImpl : public MatrixImpl
    {
      vector< vector<double> > values;
    public:
      //Typspezifische implementierung
    };
    
    //==========
    
    int main()
    {
    Matrix M;
    M.loadImpl(new GenericMatrixImpl<double>);
    // mit der double-matrix rumspielen
    M.loadImpl(new GenericMatrixImpl<complex>);
    // mit ner complex-Matrix rumspielen...
    }
    

    Wuesste allerdings nicht, wozu sowas gut sein sollte. Denn von der einen Matrix zur anderen gibts keine Konvertierung, so dass bei einem loadImpl die alte matrix futsch ist. Sprich: im Nachhinein den verarbeiteten Typ zu aendern, ist nicht wirklich moeglich, auch mit templates nicht.

    Das einzige was du machen kannst, ist ein Matrixtemplate zu schreiben mit einer Konvertierungsfunktion, die dir eine Matrix mit einem anderen typ ausspuckt:

    template<class T>
    class Matrix {
    //...
    
    public:
      template<class T2>
      Matrix<T2> convert() {
        //Matrix aufbauen, die einen anderen typ verwaltet.
      };
    };
    
    main() {
      Matrix<double> md;
      Matrix<complex> = md.convert<complex>();
    }
    

    Dabei musst du allerdings eventuell eine tremplate firend deklaration einfuegen, da Matrix<T> sonst nicht in den private Eingeweiden von Matrix<T2> rumfuhrwerken darf.



  • danke vielmals - ich bin mir nicht sicher ob wir aneinander vorbeireden.

    Ich versuche es nochmals zu erklären:
    ich habe eine klasse die im moment noch so aussieht (unter anderem):

    class my_class
    {
       double** arr1;
       double* arr2;
    }
    

    jetzt weiß ich dass ich nur 2 inputs haben kann: double und eine struktur my_struct.

    Abhängig vom input switche ich über if-else und wollte jetzt abhängig vom input
    das array arr1 und arr2 entweder mit double oder my_struct werten füllen.

    dazu wollte ich in der klasse
    eine std::vector<T*> und std::vector<T> verwenden war aber glaube ich nicht geht weil der compiler schreit:

    Compressed_Lines.h:13: Fehler: »T« wurde in diesem Gültigkeitsbereich nicht definiert
    13: Fehler: Templateargument 1 ist ungültig
    13: Fehler: Templateargument 2 ist ungültig
    

    hab ich ein chance? 🙂



  • hmm wir könnten dir mehr helfen, wenn du den COde zeigen würdest ...

    Bedenke auch, dass templates immer zur Compilezeit ausgewertet werden und vergiss die typenames nicht bei abhängigen Typen.



  • ok vielleihct noch genauer zu meinen klassen:

    class Matrix
    {
    
    	public:
    
    		//viele member variablen.....etc...
    
    		/// Number of columns/rowd
    		int n;                     
    
    		/// The columns and rows of the submatrix
    		Lines *c_lines;   
    };
    
    class Lines
    {
    
    	public:        
    
    		// viele member variablen....
    
    		double **arr;
    
    		double *arr_buf;
    };
    

    die verwendung sollte nun so aussehen:

    int main(...) 
    {
         Matrix *m;
    
         //einige berechnungen und das einlesen des inputs
        if( input_ist_double)
             m->c_lines->arr = new double[...];
        else //input ist z.B my_struct
             m->c_lines->arr = new my_struct[...];
    
        //Ab hier wird nur noch mit einer initialisierten variante weitergerechnet
       //also entweder double oder my_struct
    }
    


  • Ich probiere den vorschlag von pumuckl aus - aber ich scheitere. Mein code sieht so aus:

    Ich scheitere an der verwendung.
    Was ich brauche/will ist:

    Ich will ein Matrix OBjekt. Matrix objekte haben ein pointer auf ein objekt Compressed_Lines. Compressed_Lines Objekte haben ein template array.

    Je nach input will ich das Matrix OBjekt mit einem Pointer auf eine compressed_Lines objekt dass einen input-abhängigen vector hat.
    Also falls input double dann will ich so auf das double arr!!!! zugreifen:

    a = Matrix->c_lines->arr[2]
    

    hier main.cpp

    //C++ includings
    #include <iostream>
    #include <vector>
    
    int main(int argc, char *argv[])
    {
    	std::cout << "jjj" << std::endl;
    
    	int a = 1;
    
    // 	MatrixImpl * m_impl;
    
    	if ( a == 1)
    	{
    		Matrix<double> ob_matrix;
    		std::cout << "a = 1: reell" << std::endl;
    
    //wie soll ich hier zugreifen?????
    // 		ob_matrix.loadImpl(new Compressed_Lines<double*>);
    // 		ob_matrix.c_lines.arr = new std::vector<double*>();
    	}
    	else
    	{
    		std::cout << "a = 0: complex" << std::endl;
    // 		ob_matrix.loadImpl(new Compressed_Lines<int>); 
    	}
    	return EXIT_SUCCESS;
    }
    

    hier ist Matrix.h

    #ifndef GUARD_MATRIX_H
    #define GUARD_MATRIX_H
    
    #include "Compressed_Lines.h"
    
    template <class T>
    class Matrix
    {
    	MatrixImpl* impl;
    	public:  
    
    		Compressed_Lines<T*> c_lines;      
    
    		void Init_Matrix(Matrix *A);
    
    		Matrix* New_Matrix();
    };
    #endif
    

    hier ist matrix.cpp

    //file includings
    #include "Matrix.h"
    
    //C++ includings
    #include <iostream>
    #include <stdexcept>
    
    void
    Matrix::Init_Matrix(Matrix *A)
    {
    // 	A->c_lines = NULL;
    
    }
    
    Matrix* 
    Matrix::New_Matrix()
    {
    	Matrix *A = new Matrix::Matrix();
    	Init_Matrix(A);
    
    	return A;
    }
    

    Hier ist compressed_lines.h

    #ifndef GUARD_COMPRESSED_LINES_H
    #define GUARD_COMPRESSED_LINES_H
    
    #include <vector>
    
    class MatrixImpl {
      //abstrakte Basisklasse die eine typunabhaengige 
    	//Schnittstelle der virtuellen Funktionen liefert, die von Matrix verwendet werden.
    	public:
    		virtual ~MatrixImpl(){};
    };
    
    template<class T>
    class Compressed_Lines : public MatrixImpl
    {
    
    	public:        
    
    		// This 2D array holds the column-arrays named A_buf
    		std::vector<T*> arr;
    
    		// This is the buffer array which hold the values of the specific
    		// column of the matrix, it is accessed via the pointers of A.
    		std::vector<T> col_buf;
    
    		Compressed_Lines *	New_Compressed_Lines(int nbr_cols);
    
    	private:
    
    		void 	Init_Compressed_Lines(Compressed_Lines *cls,
    									  int nbr_cols);
    };
    #endif
    

    hier ist compressed_lines.cpp

    //file includings
    #include "Compressed_Lines.h"
    
    //C++ includings
    #include <iostream>
    
    void
    Compressed_Lines::Init_Compressed_Lines(Compressed_Lines *cls,
    									    int nbr_cols)
    {
    	int i;
    }
    
    Compressed_Lines *
    Compressed_Lines::New_Compressed_Lines(int nbr_cols)
    {
    	Compressed_Lines *cls;
    
    	cls = new Compressed_Lines::Compressed_Lines();	
    	Init_Compressed_Lines(cls, nbr_cols);
    
      	return cls;
    }
    


  • Ja also ich habe es jetzt so gemacht und es funktionert.
    Ich wäre froh wenn mir jemand sagen könnte ob es günstiger geht bzw. ob ich da völligen schwachsinn gemacht habe....danke

    main.cpp

    //file includings
    #include "Matrix.h"
    
    //C++ includings
    #include <iostream>
    #include <stdexcept>
    
    #include <vector>
    
    //Macros
    #define EXIT_FAILURE 1
    
    int main(int argc, char *argv[])
    {
    	std::cout << "jjj" << std::endl;
    
    	int a = 2;
    
    // 	MatrixImpl * m_impl;
    
    	if ( a == 1)
    	{
    		Matrix<double> *A;
    		std::cout << "a = 1: reell" << std::endl;
    
    		Compressed_Lines<double> o_cl;
    		Compressed_Lines<double> *lines = o_cl.New_Compressed_Lines(5);
    
    		A->c_lines = lines;
    		A->c_lines->col_buf[0] = 9.987;
    
    		std::cout << A->c_lines->col_buf[0] << std::endl;
    
    	}
    	else
    	{
    		std::cout << "a = 0: complex" << std::endl;
    // 		ob_matrix.loadImpl(new Compressed_Lines<int>); 
    
    		Matrix<COMPLEX> *A;
    
    		Compressed_Lines<COMPLEX> o_cl;
    		Compressed_Lines<COMPLEX> *lines = o_cl.New_Compressed_Lines(5);
    
    		COMPLEX complex;
    
    		complex.real = 1.55556;
    		complex.imag = 8.334;
    
    		A->c_lines = lines;
    		A->c_lines->col_buf[0] = complex;
    
    		std::cout << A->c_lines->col_buf[0].real <<  " " << A->c_lines->col_buf[0].imag << std::endl;
    
    	}
    
    	return EXIT_SUCCESS;
    }
    

    Matrix.h

    class Abstract_Matrix
    {
    	public:
    
    			/// Number of columns/rowd
    		int n;                   	    
    
    		void Init_Matrix(Abstract_Matrix *A);
    
    		Abstract_Matrix* New_Matrix();
    };
    
    struct COMPLEX
    {
    	double real;
    	double imag;
    };
    
    template <class T>
    class Matrix : Abstract_Matrix
    {
    	public:
    
    		/// The columns and rows of the submatrix
    		Compressed_Lines<T> *c_lines;      
    
    		void Init_C_Lines(int nmb)
    		{
    			c_lines = NULL;
    // 			c_lines = NULL;	
    // 			c_lines[0] = 8.99;
    		}
    };
    #endif
    

    Compressed_Lines.h

    template<class T>
    class Compressed_Lines 
    {
    
    	public:        
    
    		Compressed_Lines<T>(){}
    
    		~Compressed_Lines<T>(){}
    
    		// This 2D array holds the column-arrays named A_buf
    		std::vector<T*> arr;
    
    		// This is the buffer array which hold the values of the specific
    		// column of the matrix, it is accessed via the pointers of A.
    // 		std::vector<T> col_buf;
    		T*	col_buf;
    
    		Compressed_Lines<T>*
    		New_Compressed_Lines(int nbr_cols)
    		{
    			Compressed_Lines<T> *cls;
    
    			cls = new Compressed_Lines<T>();	
    
    // 			cls->col_buf.push_back(3.3);
    // 			cls->col_buf.push_back(4.3);
    			cls->col_buf = new T[nbr_cols];
    
    			return cls;
    		}
    
    	private:
    
    		void 	Init_Compressed_Lines(Compressed_Lines<T> *cls,
    									  int nbr_cols);
    };
    #endif
    


  • Hmm....so kann ich allerdings nicht auf die Methoden von Abstract_Matrix über Matrix zugreifen.

    Ich wollte über ein Matrix-Objekt auf die TypUNspezifischen Methoden/Variablen von Abstract_Matrix zugreifen. Geht das nicht über:

    Matrix<double> ob_matrix;
    
    Matrix<double> *A;
    
    ob_matrix.Init_Matrix(A);
    

    😕


Anmelden zum Antworten