Scope-Operator
-
piwi133 schrieb:
Je nachdem, welchen Wert val besitzt, soll doSomething von Datei file_1.cpp oder file_2.cpp aufgerufen werden. Beide Dateien enthalten die gleiche Signatur, nur deren Funktion ist natürlich unterschiedlich!
Das verstehe ich nicht ganz. Was meinst du mit Dateisignatur (sollte das Funktionssignatur heissen?), und inwiefern unterscheiden sich die Funktionen? Nur in ihrer internen Implementierung?
Sind die Konstruktoren Teile unterschiedlicher Templatespezialisierungen? Wenn nicht, wieso willst du überhaupt zwischen verschiedenen Konstruktoren auswählen? Ich wäre froh um ein etwas ausführlicheres Codestück, das vor allem die Unterschiede der Funktionen in Abhängigkeit der Templateparameter aufzeigt.
-
Fehlen da vielleicht die Klammern hinter Derivation<val> :: doSomething**()** ?
-
DocShoe schrieb:
Fehlen da vielleicht die Klammern hinter Derivation<val> :: doSomething**()** ?
Ich glaube eher, das ist ein Flüchtigkeitsfehler. Beispielsweise hat piwi133 bei der
Base::build()-Funktion auch vergessen, einen Wert zurückzugeben. Zudem würde mich wundern, wenn das so auf Linux kompiliert werden konnte.piwi133, ich fände es trotzdem gut, du könntest dich auf solche Dinge etwas achten, das erspart auch wilde Spekulationen. Am besten wäre ein kleines, aber vollständiges und vor allem korrektes Codebeispiel, das deine Problematik verdeutlicht. Und nimm vielleicht lieber die [cpp]- anstelle der [code]-Tags, das ist übersichtlicher.

-
Unterschiedliche Implementationen der gleichen Memberfunktion in verschiedenen ÜEs?
-
so, also hier nochmal alles mit Originalquelltext (wie gesagt, es handelt sich dabei um eine riesige Bibliothek):
Aufruf der Fkt. im Startprogramm:
AutoPtr<FEBase> fe (FEBase::build(dim, fe_type));Implementierung von Fkt. build(nur relevanter switch-case):
AutoPtr<FEBase> FEBase::build (const unsigned int dim, const FEType& fet) { switch (dim) { case 2: { case LAGRANGE: { AutoPtr<FEBase> ap(new FE<2,LAGRANGE>(fet)); return ap; } } } }Konstruktor von Klasse FE:
template <unsigned int Dim, FEFamily T> inline FE<Dim,T>::FE (const FEType& fet) : FEBase (Dim,fet), last_side(libMesh::invalid_uint), last_edge(libMesh::invalid_uint) { libmesh_assert (T == fe_type.family); }später im Startprogramm erfolgt er Aufruf von fe->reinit(). Darin wird die Funktion n_shape_functions() aufgerufen, die folgendermaßen in fe.h (Klasse FE) implementiert ist:
static unsigned int n_shape_functions (const ElemType t, const Order o) { return (FE<Dim,T>::n_dofs (t,o)); }Und genau dieser Aufruf ist das Problem. Der Wert von T ist 0, es wird aber immer die Funktion von Wert 5 aufgerufen!
Diese heißt beiden Fällen n_dofs() und enthält die gleiche Signatur, ist aber in unterschiedliche .cpp-files implementiert.Deklariert wird sie in Klasse FE folgendermaßen:
static unsigned int n_dofs(const ElemType t, const Order o);Ich hoffe, dass es nun etwas besser verständlich ist!
Grüße
Stefan
-
piwi133 schrieb:
Und genau dieser Aufruf ist das Problem. Der Wert von T ist 0, es wird aber immer die Funktion von Wert 5 aufgerufen!
Diese heißt beiden Fällen n_dofs() und enthält die gleiche Signatur, ist aber in unterschiedliche .cpp-files implementiert.Deklariert wird sie in Klasse FE folgendermaßen:
static unsigned int n_dofs(const ElemType t, const Order o);Und diese Definitionen sehen wie aus (der eigentliche Funktionskörper allerdings interessiert nicht)?
-
template <unsigned int Dim, FEFamily T> unsigned int FE<Dim,T>::n_dofs(const ElemType t, const Order o) {}FEFamily ist nur ein enum.
-
Welche Spezialisierung wird wo und in welcher ÜE instantiiert? Technisch gesehen wird hier bereits die ODR verletzt, wenn die Definitionen in den verschiedenen ÜEs verschieden sind.
-
in extra Datei (fe_macro.h):
#define INSTANTIATE_FE(_dim) template class FE< (_dim), CLOUGH>; \ template class FE< (_dim), HERMITE>; \ template class FE< (_dim), HIERARCHIC>; \ template class FE< (_dim), LAGRANGE>; \ template class FE< (_dim), MONOMIAL>; \ template class FE< (_dim), BERNSTEIN>; \ template class FE< (_dim), SZABAB>; \ template class FE< (_dim), XYZ> #define INSTANTIATE_MBRF(_dim,_t) \ template unsigned int FE<_dim,_t>::n_dofs_at_node(ElemType,Order,unsigned int); #endifin Funktion fe.c:
INSTANTIATE_FE(1); INSTANTIATE_FE(2); INSTANTIATE_FE(3);und in den unterschiedlichen .cpp-Files (hier z.B. fe_lagrange.cpp):
// Explicit instantiation of member functions INSTANTIATE_MBRF(1,LAGRANGE); INSTANTIATE_MBRF(2,LAGRANGE); INSTANTIATE_MBRF(3,LAGRANGE);
-
Zusammengefasst sieht das also ungefähr so aus?
// header.h enum my_enum { my_enum1, my_enum2 }; template <unsigned Dim, my_enum T> class X { ... static unsigned n_dofs(Foo x, Bar y); ... }; //ÜE1.cpp include "header.h" // definiere Member von X außer n_dofs ... // instantiiere explizit: template class X<1,my_enum1>; template class X<1,my_enum2>; template class X<2,my_enum1>; template class X<2,my_enum2>; //ÜE2.cpp include "header.h" template <unsigned Dim, my_enum T> unsigned X<Dim,T>::n_dofs(Foo x, Bar y) { do_something1(); } template X<1,my_enum1>::n_dofs; template X<2,my_enum1>::n_dofs; //ÜE3.cpp include "header.h" template <unsigned Dim, my_enum T> unsigned X<Dim,T>::n_dofs(Foo x, Bar y) { do_something2(); } template X<1,my_enum2>::n_dofs; template X<2,my_enum2>::n_dofs;Das verletzt, wie gesagt, die ODR. Man kann sich vorstellen, vorausgesetzt, es finden keine impliziten Instantiierungen statt. Das ist allerdings eine Bedingung auf man das Design niemals aufbauen sollte (das Hinzufügen einer Komponente kann zum Zusammenbruch führen, ohne dass sich das beim Compilieren/Linken bemerkbar macht).
Richtig wäre, hier von vornherein nur die Spezialisierungen zu definieren, die auch instantiiert werden sollen/müssen.
-
so, habe mich nochmals um das Problem gekümmert!
Habe ein kleines Testprogramm geschrieben und siehe da, es funktioniert einwandfrei!Hier das Prog:
main.C
#include <iostream> #include "fe.h" using namespace std; int main() { FE<2,LAGRANGE> fe; //oder FE<2,XYZ> fe; unsigned int ret=fe.n_sf(QUAD9); cout << "Family: " << ret << endl; return 0; }fe.h
#ifndef __FE_H #define __FE_H #include <iostream> #include "macro_elem.h" #include "enum.h" template <unsigned int Dim, FEFamily T> class FE { public: FE(); static unsigned int n_dofs(ElemType); unsigned int n_sf(ElemType val) { unsigned int tmp=1; tmp = FE<Dim,T>::n_dofs(val); return tmp; } }; template <unsigned int Dim, FEFamily T> inline FE<Dim,T>::FE () { printf("Im FE-constructor\n"); } #endiffe.C
#include "fe.h" #include "macro.h" INSTANTIATE_FE(2);fe_lag.C
#include "fe.h" #include "macro.h" template <unsigned int Dim, FEFamily T> unsigned int FE<Dim,T>::n_dofs(ElemType val) { printf("Ich bin in Lagrange :-)\nElem: %d\n",val); return 0; } INSTANTIATE_MBRF(2,LAGRANGE);#include "fe.h" #include "macro.h" template <unsigned int Dim, FEFamily T> unsigned int FE<Dim,T>::n_dofs(ElemType val) { printf("Ich bin in X :-(\nElem: %d\n",val); return 5; } INSTANTIATE_MBRF(2,XYZ);macro.h
#ifndef __MACRO_H #define __MACRO_H #define INSTANTIATE_FE(_dim) template class FE< (_dim), LAGRANGE>; \ template class FE< (_dim), XYZ> #define INSTANTIATE_MBRF(_dim,_t) \ template unsigned int FE<_dim,_t>::n_dofs(ElemType) #endifenum.h
#ifndef __ENUM_H #define __ENUM_H enum FEFamily { LAGRANGE=0, XYZ=5 }; #endifmacro_elem.h
#ifndef __MACRO_EELEM_H #define __MACRO_EELEM_H enum ElemType { QUAD9=9 }; #endifVerletzt dies die ODR?