Templates und verschachteltes STL-Objekt



  • Hab mich gerade mit templates etwas beschäftigt und bin auf ein Problem gestoßen, bei dem ich mich schwer tue 😃

    #include <iostream>
    #include <string>
    #include <list>
    #include <vector>
    
    template<typename T, typename U>
    class TableStyle
    {
    	private:
    
    	public:
    		void print(const T &head, const U &data);
    };
    
    template<typename T, typename U>
    void TableStyle<T, U>::print(const T &head, const U &data)
    {
    	typename T::const_iterator iterHead;
    	typename U::const_iterator iterData;
    
    	for(iterHead=head.begin(); iterHead!=head.end(); ++iterHead)
    		std::cout << iterHead->length() << std::endl;
    
    	// erst ueber std::vector
    	for(iterData=data.begin(); iterData!=data.end(); ++iterData)
    	{
    		// dann noch ueber std::list 
    		/*
    			An dieser Stelle moechte ich ueber das "innere" Objekt iterieren.
    		*/
    	}
    }
    
    int main()
    {
    	TableStyle<std::list<std::string>, std::vector<std::list<std::string> > > oTs;
    
    	std::list<std::string> head;
    	std::vector<std::list<std::string> > data;
    
    	oTs.print(head, data);
    }
    

    Wie alle sehen, hab ich als 2. Parameter ein verschachteltes Konstrukt (Instanziierung).

    Frage 1:
    - das std::string soll immer gleich bleiben und nicht durch andere Container ersetzt werden.

    Frage 2.
    - die Iteration ueber std::list bei data in der Funktion print ist mir ein Rätsel.

    Ansätze zu 1. kann ich grad net liefern. Meine Idee wäre, das alles aufzudröseln und mehrere Templateparameter zu übergeben, wobei ich den einen mit std::string fest zuweise, geht natürlich nicht 👎

    template<typename T, typename U, typename V=std::string>
    
    //[...]
    
    template<typename T, typename U, typename V>
    void TableStyle<T, U, V>::print(const T &head, const U<V> &data)
    

    zu 2. viel mir ein, ein temporäres Objekt zu erstellen, und darüber dann zu iterieren ... so:

    std::list<std::string> temp = *iterData;
    

    Wobei der vordere Teil natürlich wiederum über Templateparameter gesteuert wird.
    Das funktioniert zwar, aber geht das auch anders?

    Wäre abgefahren, wenn jemand Tipps hat. (Bitte net nach dem Sinn fragen. 🤡 und ja ... ich habs kompliziert beschrieben)



  • 🕶 suppi ... konnte Frage 2 ganz allein ohne Hilfe lösen ... total simbel

    for(iterData=data.begin(); iterData!=data.end(); ++iterData)
    	{
    		typename T::const_iterator iterCol;
    
    		for(iterCol=iterData->begin(); iterCol!=iterData->end(); ++iterCol)
    		{
    			std::cout << *iterCol << std::endl;
    		}
    	}
    


  • Das zweite geht alternativ auch über

    typename U::value_type::const_iterator iterCol;
    // anstatt
    typename T::const_iterator iterCol;
    

    Vom ersten verstehe ich den Sinn nicht ganz. Es ist zwar ohne weiteres möglich, nur std::string zu erlauben, aber std::wstring oder char * werden dann verboten, obwohl sie gleiche Funktionalität liefern und m.E. nicht aussen vor gelassen werden sollen.
    Falls du darauf beharrst: entweder du verwendest Template-Spezialisierung oder typedef'st V als std::string innerhalb der Klasse.



  • Der Sinn ist im Moment durchaus etwas fragwürdig ... ich will quasi
    folgendes erreichen:

    std::vector<std::list<std::string> > >
         |           |         |
         variabel    |         |
                     variabel  |
                               fix
    

    Meine Rechersche führte mich zum EBook "Moderne C++ Programmierung"

    http://books.google.de/books?id=Xkp2k8vyUgUC&pg=PA247&lpg=PA247&dq=c%2B%2B+verschachtelte+templateparameter&source=bl&ots=9rfANHnmB_&sig=t9GZDib46cyt5yY70l2jYJIQ4Ks&hl=de&ei=oeviTISIB86UOum80WA&sa=X&oi=book_result&ct=result&resnum=4&ved=0CDYQ6AEwAw

    und brachte bei mir folgendes sinnfreies Gewülst hervor

    template<typename T, template<template<typename V=std::string> class D> class U>
    

    Ob das nun am Ende Erfolg verspricht, werde ich bald sehen 😃



  • class TableStyle
    {
        private:
    
        public:
            template<typename T1, typename T2, typename T3> void print(const T1<std::string> &head, const T2<T3<std::string> > &data);
    };
    

    Geht das?



  • wxSkip schrieb:

    template<typename T1, typename T2, typename T3> void print(const T1<std::string> &head, const T2<T3<std::string> > &data);
    

    Geht das?

    Nein. Mit typename sagst du explizit, dass es sich bei T1 , T2 und T3 um Typnamen handelt. Du verwendest die drei Bezeichner jedoch als Templates, was keine Typen sind.



  • Nexus schrieb:

    wxSkip schrieb:

    template<typename T1, typename T2, typename T3> void print(const T1<std::string> &head, const T2<T3<std::string> > &data);
    

    Geht das?

    Nein. Mit typename sagst du explizit, dass es sich bei T1 , T2 und T3 um Typnamen handelt. Du verwendest die drei Bezeichner jedoch als Templates, was keine Typen sind.

    Schade. Dann bleibt wohl für sowas nur die Workaround-Lösung, oder?



  • Naheliegend wären Template-Template-Parameter, welche hier jedoch nicht eingesetzt werden können, da die Anzahl der Template-Parameter bei STL-Containern nicht festgelegt ist (Implementierungen dürfen zusätzliche Default-Parameter verwenden).

    Grundsätzlich kann die Klasse so aussehen:

    template <template <typename T> class OuterType, template <typename T> class InnerType>
    struct MyClass
    {
    	typedef typename InnerType<std::string>::Type Inner;
    	typedef typename OuterType<Inner>::Type       Outer;
    };
    

    Verwende dann intern die Typedefs, z.B. zur Deklaration von Membervariablen und Iteratoren. Benutzt werden können std::vector und std::list dennoch, aber über eine Indirektion:

    template <typename T>
    struct StdVector
    {
    	typedef std::vector<T> Type;
    };
    
    template <typename T>
    struct StdList
    {
    	typedef std::list<T> Type;
    };
    
    int main()
    {
    	MyClass<StdVector, StdList> m;
    }
    


  • Hey Nexus ... super Danke. 👍 Ich glaub, des passt, so wie ich es brauch.
    Hab es mal eben auf mein Zeugs angewendet. Hoffe das hab ich richtig umgesetzt *g*
    Zumindest funktioniert es.

    template <typename T>
    struct StdVector
    {
        typedef std::vector<T> Type;
    };
    
    template <typename T>
    struct StdList
    {
        typedef std::list<T> Type;
    };
    
    template <template <typename T> class InnerType, template <typename T> class OuterType>
    class TableStyle
    {
    	private:
    		typedef typename InnerType<std::string>::Type Inner;
    		typedef typename OuterType<Inner>::Type       Outer;
    
    		public:
    			void print(const Inner &head, const Outer &data);
    };
    
    template <template <typename T> class InnerType, template <typename T> class OuterType>
    void TableStyle<InnerType, OuterType>::print(const Inner &head, const Outer &data)
    {
    	typename Inner::const_iterator iterHead;
    	typename Outer::const_iterator iterData;
    
    	//[...]
    }
    
    int main()
    {
    	TableStyle<StdList, StdVector> oTs;
    
    	std::list<std::string> head;
    	std::vector<std::list<std::string> > data;
    
    	oTs.print(head, data);
    }
    

Log in to reply