Bedingte Kompilierung mit Templates



  • Hallo,

    ich möchte anhand bedingter Kompilierung 2 separate files mit funktionen führen die gleich signatur haben aber unterschiedliches anstellen.

    /serial/Impl_A.h
    /parallel/Impl_B.h

    dann ein file Impl.h

    #ifdef PARALLEL
    #include parallel/Impl_B.h
    #else
    #include serial/Impl_A.h
    #end
    

    z.B. steht in Impl_A.h

    inline void
    Env_Stats(int& a, double& b)
    {
        a = 9;
        b = 10;
    }
    

    und in Impl_B.h

    inline void
    Env_Stats(int& a, double& b)
    {
        a = 1;
        b = 0;
    }
    

    Damit habe ich die sachen die bedingt kompiliert werden an separater stelle und nur 1 Code der unabhängig ist.
    Ich habe dann z.B. eine templatebasierte Klasse:

    #include "Impl.h"
    
    template <class T>
    class MyClass
    {
         public:
            MyClass<T>(int a, int b);
    };
    
    #include "MyClass.imp"
    

    wobei MyClass.imp so aussieht:

    MyClass<double>::MyClass(int a, int b)
    {
         Env_Stats(a,b);
    }
    

    Ich bekomme beim kompilieren folgenden fehler:

    In constructor »MyClass<T>::MyClass(int, int)«:
    MyClass.imp:43 Fehler: es gibt keine Argumente für »Env_Stats«, die von einem Templateparameter abhängen, weshalb eine Deklaration von »Env_Stats« verfügbar sein muss
    MyClass.imp:43: Fehler: (mit »-fpermissive« wird G++ den Code akzeptieren, aber die Verwendung eines nicht deklarierten Namens ist veraltet)
    

    Ich verstehe überhaupt nicht warum - Env_Stats ist doch verfügbar und wird doch in Impl.h bzw. Impl_B.h deklariert. Wo liegt mein Fehler?

    Vielen Dank für die Hilfe



  • sorry - MyClass.imp sieht so aus (siehe template-parameter!!!):

    MyClass<T>::MyClass(int a, int b)
    {
         Env_Stats(a,b);
    }
    


  • public:
            MyClass<T>(int a, int b);
    

    Was sucht das " <T> " da? Weg damit. Wieso überhaupt ein Template? Du musst schon das Template für Env_stats benutzen, sagt der Compiler doch. Ohne diese Abhängigkeit geht's nicht.



  • Danke für die Antwort aber ihc verstehe sie leider nicht.
    Eine Template-Methode oder den konstruktor einer template klasse schreibt man doch so oder nicht?

    also für gewöhnlich klappt bei mir immer

    template <class T>
    A
    {
    public:
          A<T>() { //something 
          };
    };
    


  • wie willst du einen "int" in eine referenz auf double konvertieren (parameter b)? das kann nicht gehen. mit templates hat das garnix zu tun.



  • gäbe es eine alternative wie ich das hinbekommen könnte??



  • Ok also nochmal - jetzt in richtiger fassung weil ich oben nochmal nen fehler gefunden hab in meinem beipsiel:

    /serial/Impl_A.h
    /parallel/Impl_B.h

    dann ein file Impl.h

    #ifdef PARALLEL
    #include parallel/Impl_B.h
    #else
    #include serial/Impl_A.h
    #end
    

    z.B. steht in Impl_A.h

    inline void
    Env_Stats(int& a, int& b)
    {
        a = 9;
        b = 10;
    }
    

    und in Impl_B.h

    inline void
    Env_Stats(int& a, int& b)
    {
        a = 1;
        b = 0;
    }
    

    Damit habe ich die sachen die bedingt kompiliert werden an separater stelle und nur 1 Code der unabhängig ist.
    Ich habe dann z.B. eine templatebasierte Klasse:

    #include "Impl.h"
    
    template <class T>
    class MyClass
    {
         public:
            MyClass<T>();
         int ma,mb;
    };
    
    #include "MyClass.imp"
    

    wobei MyClass.imp so aussieht:

    MyClass<T>::MyClass()
    {
         Env_Stats(ma,mb);
    }
    

    habe ich so eine chance? der fehler ist immer noch der gleich natürlich...aber warum? Env_Stats hängt ja nicht von einem template ab...? 😕



  • bedingter Kompilierung

    Das ist aber ein Linkerproblem. Exportiere die Funktion in einer Headerdatei und die unterschiedlichen Implementation liegen halt in unterschiedlichen cpp-Dateien. Linke diese entsprechend deinen Wuenschen dazu.

    Und das beim include guard heisst #endif.



  • Ok - also ich habe jetzt mal ein Minimalbeispiel entstellt:

    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.h"
    #else
    #define ENV_WORLD void*
    #       include "serial/Impl_SERIAL.h"
    #endif
    
    #endif
    

    Matrix.h

    #ifndef GUARD_MATRIX_H
    #define GUARD_MATRIX_H
    
    #include "Impl_Env.h"
    
    template <class T_Field>
    class Matrix
    {
    
        public:
    
            /// Empty Constructor
                Matrix<T_Field>(){};
                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)
    {
        Env_Stats(num_procs, my_id);
        std::cout << num_procs << std::endl;
    }
    

    Impl_MPI.h

    #ifndef IMPL_MPI_H
    #define IMPL_MPI_H
    
    //file includings
    #include "../Matrix.h"
    
    inline void
    Env_Stats(ENV_WORLD world, int& num_procs, int& my_id)
    {
         num_procs = 3;
    }
    
    #endif
    

    Impl_SERIAL.h

    #ifndef IMPL_SERIAL_H
    #define IMPL_SERIAL_H
    
    //file includings
    #include "../Matrix.h"
    
    inline void
    Env_Stats(ENV_WORLD world, int& num_procs, int& my_id)
    {
        num_procs = 2;
    }
    
    #endif
    

    Die Meldung mit meinem g++ ist:

    parallel/../Matrix.imp: In constructor »Matrix<T_Field>::Matrix(void*, int, int)«:
    parallel/../Matrix.imp:14: Fehler: es gibt keine Argumente für »Env_Stats«, die von einem Templateparameter abhängen, weshalb eine Deklaration von »Env_Stats« verfügbar sein muss
    parallel/../Matrix.imp:14: Fehler: (mit »-fpermissive« wird G++ den Code akzeptieren, aber die Verwendung eines nicht deklarierten Namens ist veraltet)
    


  • Liesst du dir die Beitraege ueberhaupt durch? Auch ist dein Problem einfach nur, dass die Parameter von Env_Stat nicht deklariert wurden, num_procs und my_id sind im Konstruktor von Matrix unbekannt.



  • doch doch - ich lese sie. danke hierfür schonmal.

    Auch mit der Deklaration der paramter im kontstruktor mit:

    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(num_procs, my_id);
        std::cout << num_procs << std::endl;
    }
    

    bleibt der fehler bestehen.

    Deinen Post mit der auslagerung in einen header und einer spezialisierung versthe ich leider nicht. Ich habe doch Env_Stats in einem Header und brauche keine spezialisierung in einer cpp datei da Env_Stats doch nicht template-abhängig ist...??



  • Du hast nicht verstanden, warum normalerweise C++ Programme in Header und cpp Dateien aufgetrennt werden.

    http://gpwiki.org/index.php/Programming_Techniques:C/CPP_Header_File_Convention
    http://stackoverflow.com/questions/333889/in-c-why-have-header-files-and-cpp-files



  • Vielen Dank für die Links - ich habe sie gelesen und versuche jetzt den Transfer der mich nicht leicht fällt....



  • 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.


Anmelden zum Antworten