Komplexe Templates führen zu Compilerfehler - warum?



  • Hallo alle zusammen,

    ich versuche derzeit eine Art "Event-Klasse" zu schreiben, die es mir ermöglicht beliebige Funktions-Pointer mit einem Fixen-Parameter in eine Liste zu speichern.

    Das heißt symbolisch:
    void funktion( void *fixerParameter, int variablerParameter );
    funktionsListe->add( &funktion, meinFixerWert )

    Später beim aufruf ist es dann: funktionsListe->call( 12345 );

    Die fixen Parameter benutze ich sogesehen als festen Pointer auf eine Klasseninstanz. Aber das ist was anderes und funktioniert auch.

    Soweit so gut, dafür habe ich nun folgende Struktur, die den Funktionspointer und den fixen Wert speichert:

    template<typename T> struct PKSignalContainer
    {
        PKSignalContainer<T>() {}
        PKSignalContainer<T>(T m, void *t){ method=m; instance=t; }
    
        T      method;
        void*  instance;
    };
    

    Der Templatetyp "T" gibt hierbei den Typ des Funktionszeigers an. Außerdem gibt es eine Basis-Klasse für alle Signalklassen:

    template<typename T> struct PKSignalBase {
    protected:
        std::vector< PKSignalContainer<T> > events;
    
    public:
        void add( void *meth, void *inst ) {
            events.push_back( PKSignalContainer<T>( meth, inst) );
        }
    
        // ...
    };
    

    Auch hier gibt "T" den Typen des Funktionszeigers an. Nun zum eigentlichem Signal.

    Fall 1: Signale OHNE Parameter

    struct PKSignal : public PKSignalBase<void(*)(void*)> {
        void call( ) {
            std::vector< PKSignalContainer<void(*)(void*)> >::iterator it;
            for( it=events.begin(); it!=events.end(); it++ ) {
                it->method( it->instance );
            }
        }
    };
    

    ⚠
    Diese Struktur funktioniert problemlos. Jetzt kommt mein eigentliches Problem:

    Fall 2: Signal mit einem Parameter

    template<typename T1> struct PKSignal1 : public PKSignalBase<void(*)(void*,T1)> {
    public:
    	void call( T1 v1 ) {
    		// Hier passiert es
    		std::vector< PKSignalContainer<void(*)(void*,T1)> >::iterator it;
    		for( iterator it=events.begin(); it!=events.end(); it++ ) it->method( it->instance, v1 );
    	}
    };
    

    Gedanke dahinter war, dass ich flexible Signale definieren kann. Beispiel:
    PKSignal1< int > SignalMitIntParameter;
    PKSignal1< float > SignalMitFloatParameter;

    Diese Struktur führt zu einem Fehler `error: expected `;' before "it"` in der Zeile, in der ich den Iterator definiere.

    Seltsamerweise funktioniert das Ganze wiederum problemlos wenn ich in jener Zeile das 'T1' durch 'int' Beispielsweise ersetze. Ich habe es auch schon mit typedefs innerhalb der Klassen probiert - aber alles klappt bislang leider nicht.

    Jetzt bräuchte ich doch mal einen Rat. Ich benutze als Compiler g++ version 3.4.2 (mingw-special).

    Nochmal zum rauskopieren hier der gesamte Quellcode in meiner jetzigen - unkommentierten - Version.

    #include <vector>
    
    template<typename T> struct PKSignalContainer
    {
    	PKSignalContainer<T>() {}
    	PKSignalContainer<T>(T m, void *t){ method=m; instance=t; }
    
    	T	method;
    	void*	instance;
    };
    
    template<typename T> struct PKSignalBase
    {
    protected:
    	std::vector< PKSignalContainer<T> > events;
    
    public:
    	void add( void *meth, void *inst ) {
    		events.push_back( PKSignalContainer<T>( meth, inst ) );
    	}
    	void clear( ) {
    		events.clear( );
    	}
    }; 
    
    struct PKSignal : public PKSignalBase<void(*)(void*)> {
    	void call( ) {
    		std::vector< PKSignalContainer<void(*)(void*)> >::iterator it;
    		for( it=events.begin(); it!=events.end(); it++ ) it->method( it->instance );
    	}
    };
    
    template<typename T1> struct PKSignal1 : public PKSignalBase<void(*)(void*,T1)> {
    public:
    	void call( T1 v1 ) {
    		// Hier passiert der Fehler, es sei denn ich ersetze T1 durch einen fixen Typ
    		std::vector< PKSignalContainer<void(*)(void*,T1)> >::iterator it;
    		for( iterator it=events.begin(); it!=events.end(); it++ ) it->method( it->instance, v1 );
    	}
    };
    

    Über kleine Tipps wäre ich dankbar 🙂 Vielleicht auch eine sauberere Lösung als dieses hier die dann auch funktioniert *g*

    Vielen Dank im voraus für jede Hilfe!



  • Da du das vector-template nicht vollständig instantiierst, ist vector<.......>::iterator ein abhängiger Name und muss als typ gekennzeichnet werden -> typename

    template<typename T1> struct PKSignal1 : public PKSignalBase<void(*)(void*,T1)> {
    public:
        void call( T1 v1 ) {
            // Hier typename einbauen!
            typename std::vector< PKSignalContainer<void(*)(void*,T1)> >::iterator it;
            for( /*das iterator hier war zu viel*/ it=events.begin(); it!=events.end(); it++ ) it->method( it->instance, v1 );
        }
    };
    

    Zur Vereinfachung würde ich sowas machen:

    template<typename T> struct PKSignalBase {
    protected:
        std::vector< PKSignalContainer<T> > events;
        typedef typename std::vector< PKSignalContainer<T> >::iterator eventiter;
    
        // ...
    };
    

    und dann den eventiter-typedef in den abgeleiteten Klassen nutzen.


Anmelden zum Antworten