Bedingte Kompilierung mit Templates



  • Ich steh auf dem Schlauch.
    Ich versuche es im Moment mit der auslagerung in cpp dateien so:

    main.cpp

    #include "Impl_Env.h"
    #include "Matrix.h"
    #include <iostream>
    #include <stdexcept>
    
    int main(int argc, char *argv[])
    {
        int                 num_procs,
                            my_id;
    
        int a = 9;
        int b = 8;
        Matrix<int>*     A_REAL    = new Matrix<int>(ENV_WORLD,a,b);
    #ifdef ENV_MPI
                            std::cout << "PARALLEL" << std::endl;
    #else
                            std::cout << "SERIAL" << std::endl;
    #endif
    
    }
    

    Impl_Env.h

    #ifndef IMPL_ENV_H
    #define IMPL_ENV_H
    
    #ifdef ENV_MPI
    #       include <mpi.h>
    #define ENV_WORLD void*
    #       include "parallel/Impl_MPI.cpp"
    #else
    #define ENV_WORLD void*
    #       include "serial/Impl_SERIAL.cpp"
    #endif
    
    #endif
    

    Matrix.h

    #ifndef GUARD_MATRIX_H
    #define GUARD_MATRIX_H
    
    #include "Impl_Env.h"
    #include "test.h"
    
    template <class T_Field>
    class Matrix
    {
    
        public:
    
            /// Empty Constructor
                Matrix<T_Field>(){    num_procs = 0;
                        my_id = 0;};
                Matrix<T_Field>(ENV_WORLD       world_m,
                                const int        nbr_cols,
                                const int        nbr_rows);
                ~Matrix<T_Field>(){};
            int num_procs, my_id;
    
    };
    
    #include "Matrix.imp"
    
    #endif
    

    Matrix.imp

    #include "Impl_Env.h"
    
    //C/C++ includings
    #include <string>
    #include <stdlib.h>
    #include <sstream>
    #include <iostream>
    
    template <class T_Field>
    Matrix<T_Field>::Matrix(ENV_WORLD       world_m,
                            const int        nbr_cols,
                            const int        nbr_rows)
    {
        num_procs = 0;
        my_id = 0;
        Env_Stats(world_m,num_procs, my_id);
        std::cout << num_procs << std::endl;
    }
    

    test.h

    #ifndef TEST_H
    #define TEST_H
    
    inline void
    Env_Stats(ENV_WORLD world, int& num_procs, int& my_id)
    {
    //     num_procs = 2;
    };
    
    #endif
    

    serial/Impl_SERIAL.cpp

    #include "test.h"
    
    inline void
    Env_Stats(ENV_WORLD world, int& num_procs, int& my_id)
    {
        num_procs = 2;
    }
    

    parallel/Impl_MPI.cpp

    #include "test.h"
    
    inline void
    Env_Stats(ENV_WORLD world, int& num_procs, int& my_id)
    {
         num_procs = 3;
    }
    

    Als fehlermeldung kommt:

    test.h: In function »void Env_Stats(void*, int&, int&)«:
    test.h:6: Fehler: redefinition of »void Env_Stats(void*, int&, int&)«
    parallel/Impl_MPI.cpp:5: Fehler: »void Env_Stats(void*, int&, int&)« wurde vorher hier definiert
    

    Allerdings verstehe ich (noch) nicht wo eine redefenition statt findet...


  • Mod

    test.h

    #ifndef TEST_H
    #define TEST_H
    
    inline void
    Env_Stats(ENV_WORLD world, int& num_procs, int& my_id);
    
    #endif
    


  • ah sorry - hab vergessen die geschweiften klammern wegzubringen beim header... 🙄



  • Ok - damit scheint der obige fehler beseitigt zu sein.
    Allerdings bekomme ich jetzt eine Reihe weiterer Fehler. Warum inline nicht mehr erlaubt ist verstehe ich nicht - warum plötzlich das void nicht erlaubt ist verstehe ich auch nicht:

    //main.cpp

    #include "Impl_Env.h"
    #include "Matrix.h"
    #include <iostream>
    #include <stdexcept>
    
    int main(int argc, char *argv[])
    {
        int                 num_procs,
                            my_id;
    
        int a = 9;
        int b = 8;
        Matrix<int>*     A_REAL    = new Matrix<int>(ENV_WORLD,a,b);
    #ifdef ENV_MPI
                            std::cout << "PARALLEL" << std::endl;
    #else
                            std::cout << "SERIAL" << std::endl;
    #endif
    
    }
    

    //Impl_Env.h

    #ifndef IMPL_ENV_H
    #define IMPL_ENV_H
    
    #ifdef ENV_MPI
    #       include <mpi.h>
    #define ENV_WORLD NULL
    #       include "parallel/Impl_MPI.cpp"
    #else
    #define ENV_WORLD NULL
    #       include "serial/Impl_SERIAL.cpp"
    #endif
    
    #endif
    

    Matrix.h

    #ifndef GUARD_MATRIX_H
    #define GUARD_MATRIX_H
    
    #include "Impl_Env.h"
    #include "test.h"
    
    template <class T_Field>
    class Matrix
    {
    
        public:
    
            /// Empty Constructor
                Matrix<T_Field>(){    num_procs = 0;
                        my_id = 0;};
                Matrix<T_Field>(ENV_WORLD       world_m,
                                const int        nbr_cols,
                                const int        nbr_rows);
                ~Matrix<T_Field>(){};
            int num_procs, my_id;
    
    };
    
    #include "Matrix.imp"
    
    #endif
    

    Matrix.imp

    #include "Impl_Env.h"
    
    //C/C++ includings
    #include <string>
    #include <stdlib.h>
    #include <sstream>
    #include <iostream>
    
    template <class T_Field>
    Matrix<T_Field>::Matrix(ENV_WORLD       world_m,
                            const int        nbr_cols,
                            const int        nbr_rows)
    {
        num_procs = 0;
        my_id = 0;
        Env_Stats(world_m,num_procs, my_id);
        std::cout << num_procs << std::endl;
    }
    

    serial/Impl_Serial.cpp

    #include "../test.h"
    
    inline void
    Env_Stats(ENV_WORLD world, int& num_procs, int& my_id)
    {
        num_procs = 2;
    }
    

    parallel/Impl_MPI.cpp

    #include "../test.h"
    
    inline void
    Env_Stats(ENV_WORLD world, int& num_procs, int& my_id)
    {
         num_procs = 3;
    }
    

    test.h

    #ifndef TEST_H
    #define TEST_H
    
    #include "Impl_Env.h"
    
    inline void
    Env_Stats(ENV_WORLD world, int& num_procs, int& my_id);
    
    #endif
    

  • Mod

    Poste mal die Fehlermeldung. Habe keine Lust so viele Dateien zu kopieren.

    edit: Mir scheint da aber auf den ersten Blick was mit den includes nicht zu stimmen. matrix.impl benutzt Sachen aus matrix.h ohne diese zu kennen.



  • sorry hab ich vorhin vergessen...

    parallel/../test.h:7: Fehler: Variable oder Feld »Env_Stats« als »void« deklariert
    parallel/../test.h:7: Fehler: »NULL« wurde in diesem Gültigkeitsbereich nicht definiert
    parallel/../test.h:7: Fehler: expected primary-expression before »int«
    parallel/../test.h:7: Fehler: expected primary-expression before »int«
    parallel/../test.h:7: Fehler: initializer Ausdrucksliste als zusammengesetzten Ausdruck behandelt
    parallel/Impl_MPI.cpp:4: Fehler: Variable oder Feld »Env_Stats« als »void« deklariert
    parallel/Impl_MPI.cpp:4: Fehler: »Env_Stats« als »inline« variable deklariert
    parallel/Impl_MPI.cpp:4: Fehler: redefinition of »int Env_Stats«
    parallel/../test.h:7: Fehler: »int Env_Stats« wurde vorher hier definiert
    parallel/Impl_MPI.cpp:4: Fehler: »NULL« wurde in diesem Gültigkeitsbereich nicht definiert
    parallel/Impl_MPI.cpp:4: Fehler: expected primary-expression before »int«
    parallel/Impl_MPI.cpp:4: Fehler: expected primary-expression before »int«
    Matrix.h:16: Fehler: expected `)' before »world_m«
    Matrix.imp:10: Fehler: expected constructor, destructor, or type conversion before »(« token
    main.cpp: In function »int main(int, char**)«:
    main.cpp:14: Fehler: keine passende Funktion für Aufruf von »Matrix<int>::Matrix(NULL, int&, int&)«
    

  • Mod

    Uffob schrieb:

    sorry hab ich vorhin vergessen...

    parallel/../test.h:7: Fehler: Variable oder Feld »Env_Stats« als »void« deklariert
    parallel/../test.h:7: Fehler: »NULL« wurde in diesem Gültigkeitsbereich nicht definiert
    parallel/../test.h:7: Fehler: expected primary-expression before »int«
    parallel/../test.h:7: Fehler: expected primary-expression before »int«
    parallel/../test.h:7: Fehler: initializer Ausdrucksliste als zusammengesetzten Ausdruck behandelt
    parallel/Impl_MPI.cpp:4: Fehler: Variable oder Feld »Env_Stats« als »void« deklariert
    parallel/Impl_MPI.cpp:4: Fehler: »Env_Stats« als »inline« variable deklariert
    parallel/Impl_MPI.cpp:4: Fehler: redefinition of »int Env_Stats«
    parallel/../test.h:7: Fehler: »int Env_Stats« wurde vorher hier definiert
    parallel/Impl_MPI.cpp:4: Fehler: »NULL« wurde in diesem Gültigkeitsbereich nicht definiert
    parallel/Impl_MPI.cpp:4: Fehler: expected primary-expression before »int«
    parallel/Impl_MPI.cpp:4: Fehler: expected primary-expression before »int«
    Matrix.h:16: Fehler: expected `)' before »world_m«
    Matrix.imp:10: Fehler: expected constructor, destructor, or type conversion before »(« token
    main.cpp: In function »int main(int, char**)«:
    main.cpp:14: Fehler: keine passende Funktion für Aufruf von »Matrix<int>::Matrix(NULL, int&, int&)«
    

    Du hast eine zyklische Abhängigkeit: test.h benutzt Impl_env.h benutzt Impl_XXX.cpp benutzt test.h. Das fliegt dir um die Ohren.

    Ich habe in meinem letzten Beitrag übrigens nochmal eine kleine Anmerkung reingeschrieben, während du die Fehlermeldung gepostet hast.



  • Naja, alles includiert alles wild durcheinander und ohne Plan. Normalerweise includiert man auch kein cpp-Dateien ... Du solltest dir ein gutes Tutorial suchen, das die Aufteilung von Header und cpp-Dateien behandelt.

    #define ENV_WORLD NULL
    ...
    Env_Stats(ENV_WORLD world, int& num_procs, int& my_id)
    ...
    Matrix<T_Field>::Matrix(ENV_WORLD world_m, const int nbr_cols, const int nbr_rows)
    

    ENV_WORLD ist kein Datentyp.

    Mitlerweile wuerde ich dir zu einem besseren C++ Buch/Tutorial raten.



  • Normalerweise includiert man auch kein cpp-Dateien

    hmm...danke für den hinweis. Ich möchte aber als Anfänger darauf hinweisen in der Hoffnung dass mir jemand bei diesem etwas speziellerem problem hilft:

    a) ich wüsste im moment nicht wie denn anstatt der .cpp dateien dann wieder header inkludieren sollte.

    b) wie sieht es denn aus wenn die methoden in Impl_SERIAL.cpp und IMPL_MPI.h templatebasiert sein sollen? Oder gar spezialisierungen auftreten. Dann wirds ja nochmals komplizierter...kann ich damit dann Leben mit dem EIN-Header ansatz den Knivil vorschlägt?

    Falls jemand Lust/Zeit hat würde ich mich über die Veränderung meines Minimalbeispieles freuen. Danke euch....



  • Mitlerweile wuerde ich dir zu einem besseren C++ Buch/Tutorial raten.

    hast du ein gutes buch/tutorial? Ich suche schon lange eines...



  • Du kannst mal in die FAQ - C++ des Forums schauen.


  • Mod

    Ich habe jetzt nur die letzten paar Beiträge hier im Thread gelesen, daher weiß ich nicht, ob ich jetzt irgendwas wiederhole:

    Uffob schrieb:

    a) ich wüsste im moment nicht wie denn anstatt der .cpp dateien dann wieder header inkludieren sollte.

    Die test.h ist doch anscheinend der Header der zu den Impl_XXX.cpp gehört. Also dort wo diese eingebunden werden, nimmst du test.h

    b) wie sieht es denn aus wenn die methoden in Impl_SERIAL.cpp und IMPL_MPI.h templatebasiert sein sollen? Oder gar spezialisierungen auftreten. Dann wirds ja nochmals komplizierter...kann ich damit dann Leben mit dem EIN-Header ansatz den Knivil vorschlägt?

    Ja, dann wird das mit einem gemeinsamen Header für beide unmöglich. Dann müssen die Templatedefinitionen in einen Header und entsprechende #ifdefs drumherum.



  • danke aber ich verstehe die antwort nicht.

    Die test.h ist doch anscheinend der Header der zu den Impl_XXX.cpp gehört. Also dort wo diese eingebunden werden, nimmst du test.h

    ich kann doch nicht schreiben:
    Impl_Env.h

    #ifndef IMPL_ENV_H
    #define IMPL_ENV_H
    
    #ifdef ENV_MPI
    #       include <mpi.h>
    #define ENV_WORLD void*
    #       include "test.h"
    #else
    #define ENV_WORLD void*
    #       include "test.h"
    #endif
    
    #endif
    

    und dann in einem header alle deklarationen haben und nirgendwo die Impl_.cpp einbinden. Oder meinst du dass dann in klassen oder dateien die spezifische Impl_.cpp datei eingebunden wird?
    Das würde abe bedeuten sobald man eine neue implementierung hinzufügt muss man überall wieder das #include Impl_*.cpp anpassen. damit wäre ja die ganze idee die shade hatte in diesem Thread hatte:

    http://www.c-plusplus.net/forum/viewtopic-var-t-is-236515-and-postdays-is-0-and-postorder-is-asc-and-highlight-is-ifdef-and-start-is-60.html

    egal.

    zu b).: Bist du sicher dass es keine Möglichkeit gibt? Was wäre denn eine Möglichkeit das zu bewerkstelligen? WIe geht man sonst vor wenn man eine reihe implementierungen hat? Es macht doch wenig sinn an jede stelle x mal ein #ifdef #elseif etc.... zu machen....??


  • Mod

    Uffob schrieb:

    ich kann doch nicht schreiben:
    [...]
    und dann in einem header alle deklarationen haben und nirgendwo die Impl_*.cpp einbinden.

    Doch? Das ist doch gerade das wozu Header da sind. Ich verstehe sowieso nicht, wieso du die ganze Zeit cpp Dateien einbinden willst.

    Oder meinst du dass dann in klassen oder dateien die spezifische Impl_.cpp datei eingebunden wird?
    Das würde abe bedeuten sobald man eine neue implementierung hinzufügt muss man überall wieder das #include Impl_
    .cpp anpassen. damit wäre ja die ganze idee die shade hatte in diesem Thread hatte [...] egal.

    Na eben nicht. Implementierung neu kompilieren, fertig. Das ist ja gerade das tolle an dem System.

    zu b).: Bist du sicher dass es keine Möglichkeit gibt? Was wäre denn eine Möglichkeit das zu bewerkstelligen? WIe geht man sonst vor wenn man eine reihe implementierungen hat? Es macht doch wenig sinn an jede stelle x mal ein #ifdef #elseif etc.... zu machen....??

    Du machst einmal einen #ifdef-Block um die verschiedenen Implementierungen und fertig. Das ist ja wohl nicht mehr Arbeit als du dir jetzt machst.


Anmelden zum Antworten