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.hdann 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.hdann 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...
-
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:#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
-
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&)«
-
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.