Zyklische Includes mit Templates



  • Ich habe in meinem Programm folgendes Szenario: Das Programm soll eine Simulation berechnen, basierend auf gewissen Daten. Ich muss die Simulation mehrfach laufen lassen und jeweils die Daten eines einzelnen Durchlaufs speichern.

    Dafür habe ich zwei Klassen Simulation und SimulationInstance erstellt, wobei erstere die Anfangsdaten speichert und die einzelnen Simulationsinstanzen erzeugt und laufen lässt. SimulationInstance soll nun auf die Daten von Simulation zugreifen können (ich möchte diese Daten nicht doppelt speichern).

    Folgich müssen sich Simulation und SimulationInstance gegenseitig kennen. Meine Klassen sehen wie folgt aus:

    siminstance.h

    #ifndef SIMINSTANCE_H
    #define SIMINSTANCE_H
    
    namespace mb
    {
        template <typename K> class Simulation;
    
        template <typename K>
        class SimulationInstance
        {
        public:
            SimulationInstance(const Simulation<K> * simulation);
    
        public:
            const Simulation<K> *m_simulation;
        };
    
        #include "simulation.h"
    
        template <typename K>
        SimulationInstance<K>::SimulationInstance(const Simulation<K> *simulation)
            : m_simulation(simulation)
        { }
    
    } // namespace mb
    
    #endif // SIMINSTANCE_H
    

    simulation.h

    #ifndef SIMULATION_H
    #define SIMULATION_H
    
    // Ein paar Library Includes
    
    namespace mb
    {
        template <typename K> class SimulationInstance;
    
        template <typename K>
        class Simulation
        {
        public:
    
            Simulation(const QStandardItemModel *population_model, const QStandardItemModel *forced_model,
                       const QStandardItemModel *forbidden_model);
    
            void simulate();
        private:
            // Ein paar Methoden und Felder (std::vector)
        };
    
        #include "siminstance.h"
    
        template <typename K>
        Simulation<K>::Simulation(const QStandardItemModel *population_model, const QStandardItemModel *forced_model,
                                  const QStandardItemModel *forbidden_model)
        {
            // Initialisierung
        }
    
        template <typename K>
        void Simulation<K>::simulate()
        {
            SimulationInstance<K> inst(this); // Hier tritt der Fehler auf
        }
    
    } // namespace mb
    
    #endif // SIMULATION_H
    

    Das Problem ist nun, dass ich den Fehler

    simulation.h:98: error: 'mb::SimulationInstance<int> inst' has incomplete type

    bekomme. Ich habe schon viel gegoogelt und ausprobiert aber sehe einfach nicht wo mein Fehler liegt.

    Kann mir jemand sagen wie ich das lösen kann? Bin auch für bessere Designvorschläge von Simulation und SimulationInsance offen.

    *Edit
    SimulationInstance.h heisst in Wirklichkeit siminstance.h, habs oben gefixt.



  • steht da wirklich #include "simulation.h" in der Datei simulation.h ?



  • großbuchstaben schrieb:

    steht da wirklich #include "simulation.h" in der Datei simulation.h ?

    Da steht doch gar nicht [c]#include simulation.h[/c] in der Datei simulation.h?
    Sorry, ich hatte die Files falsch angeschrieben.



  • Die Dateien inkludieren sich immer noch selbst. Davon abgesehen ist es immer eine schlechte Idee, innerhalb eines Namensraums #include -Direktiven zu haben.

    Hast du versucht, lediglich eine Datei am Anfang der anderen zu inkludieren? Templates werden ja nicht direkt kompiliert, sondern erst zum Zeitpunkt ihrer Instantiierung (wobei sich Compiler leicht unterschiedlich verhalten).



  • Nexus schrieb:

    Davon abgesehen ist es immer eine schlechte Idee, innerhalb eines Namensraums #include -Direktiven zu haben.

    Ich habe das in irgend einem C++ Artikel gelesen... genau deshalb mag ich online Artikel zu C++ nicht.

    Nexus schrieb:

    Hast du versucht, lediglich eine Datei am Anfang der anderen zu inkludieren?

    Wunderbar, hat nach etwas ausprobieren geklappt. Ich musste noch die Forward-Declaration in den Namespace mb schreiben, ansonsten meckert der Compiler.

    Vielen Dank für die Hilfe.


Anmelden zum Antworten