Template Metaprogrammierung - Typvarianten erzeugen
-
Hallo!
Ich möchte gerne 90 Versionen einer Templateklasse vom Compiler erzeugen lassen. Das soll ja so gut gehen mit Meta-Template-Programmierung. Mein Header sieht so aus:
template <typename ImageType> class XTKBox { //spitzenmäßige Klasse }; template<int DIM, int COMP> class BoxConstruction { //ImageType definieren typedef itk::Image< itk::Vector< char, COMP>, DIM > ImageType_Char; //Char-Variante erstellen XTKBox<ImageType_Char> constructMe_Char; typedef itk::Image< itk::Vector< unsigned char, COMP>, DIM > ....usw. für alle Datentypen halt.... BoxConstruction<DIM-1, COMP> continueDim; BoxConstruction<DIM, COMP-1> continueComp; }; template<int COMP> class BoxConstruction<0, COMP> { //done }; template<int DIM> class BoxConstruction<DIM, 0> { //done }; class BoxFactory { //"Aufruf" der rekursiven Klassenerstellung BoxConstruction<3,3> createBoxes; };Das kompiliert auch alles, aber der Linker kommt mit tausend Fehlermeldungen der Sorte:
undefined reference to `XTKBox<itk::Image<itk::Vector<double, 3u>, 3u> >::getVTKFromITKImage()'Der Compiler scheint also garnüscht zu erzeugen. Hat da jemand einen guten Rat?
Beste Grüße,
Christian
-
quaid schrieb:
undefined reference to `XTKBox<itk::Image<itk::Vector<double, 3u>, 3u> >::getVTKFromITKImage()'Also nach gar_nichts erzeugen sieht mir das nicht aus. Eigentlich würde ich sogar sagen: Das ist so ziemlich sexy. Immerhin ist es kein Compiler- sondern ein Linkererror.
Also, wenn dann liegt dein Fehler an der Klasse, die du mit dem Prädikat Spitzenmäßig ausgezeichnet hast und deswegen keine zeile Code zur Information brachtest

-
Oh... Äh ja, das ist ganz sicher keine Header-Only Bibliothek. Soll ich den ganzen Kram auch noch für alle Methoden machen??
Template MetaProgrammierung ist für mich Neuland, wie ich den Header konstruiere habe ich offenbar ja doch ganz gut verstanden, aber sonst...Meine Box sieht so aus:
template <typename ImageType> class XTKBox { protected: typedef itk::VTKImageImport<ImageType> ImageImportType; typedef itk::VTKImageExport<ImageType> ImageExportType; typename ImageImportType::Pointer itkImporter; typename ImageExportType::Pointer itkExporter; vtkImageImport* vtkImporter; vtkImageExport* vtkExporter; ImageType* itkImage; vtkImageData* vtkImage; public: XTKBox() {}; XTKBox(vtkImageData*); //get/set ITK Image Data void setITKImage( ImageType* input) { itkImage = input; } ImageType* getITKFromVTKImage(); //get/set VTK Image Data void setVTKImage(vtkImageData* input) { vtkImage = input; } vtkImageData* getVTKFromITKImage(); vtkImageData* getVTKImage() { return vtkImage; } };Also sone Klasse mit Funktionen halt...

-
Die implizite Instantiierung einer Klasse als solche führt nicht dazu, dass Memberfunktionen oder statische Membervariablen implizit instantiiert werden.
Ein typedef benötigt keine Definition und bewirkt daher keine Instantiierung des Typs.
Eine explizite Instantiierung wiederum muss auf Namensraumebene erfolgen und ist daher hier nicht zu gebrauchen.
-
Danke Camper, jetzt läufts. Das ist aber nicht im Sinne des Erfinders, dass jetzt der ganze Code mit im Header steht, ich will das ja gerne später verlinken, sonst ist jedes Programm was die Box benutzt gleich 12MB größer...
Was kann man da machen? Ich bin nicht grad der Compiler-Experte, wann wer was wie linked und wo welche Namensräume gelten oder so. Ich will doch nur meine 90 Varianten haben!
-
Also, da das Thema offenbar nicht so einfach ist möchte ich hier meine Lösung präsentieren, damit auch jemand was davon hat, wenn er bei seiner Suche auf das Posting hier trifft.
Um dem Compiler dazu zu bringen von allen Klassenvarianten alle Methoden zu instantiieren macht man folgendes:
Man schreibt in die .cpp Datei seiner dollen Klasse einfach eine (oder bei Bedarf mehrere hintereinandergeschaltete) Funktionen, die eben diese Typvarianten "erzeugen" und instanziiert dann ALLE Varianten in einem eigenen kleinen Gültigkeitsbereicht, am besten in einer if (true) Umgebung. Das ist wichtig, damit man die Klasse, egal welcher Typ, immer gleich nennen kann und somit ein schönes #define Makro schreiben kann was einem die Arbeit abnimmt und vor allem doppelten Code vermeidet.
Man muss nämlich bei jeder Instanz JEDE einzelne Funktion auch mal aufrufen, damit der Compiler sie auch erstellt. In das #define Makro muss man aber nur einmal jede Funktion mit reinschreiben. Das Makro ruft man dann für jede Instanziierung auf.Bei mir sieht das ganze jetzt so aus:
///------------------------------------------------------------------------------------ ///--- Make the compiler generate all different ImageType Classes and their methods --- ///------------------------------------------------------------------------------------ #define vtkITKFilter_CreateFunctionsMacro \ XTKBox<ImageType> *dummyBox = new XTKBox<ImageType>(dummyVTKImageData); \ ImageType *dummyITKImage = ImageType::New(); \ dummyBox->setITKImage( dummyITKImage ); \ dummyBox->getITKFromVTKImage(); \ dummyBox->setVTKImage( dummyVTKImageData ); \ dummyBox->getVTKFromITKImage(); \ dummyBox->getVTKImage(); //step3 template<unsigned int DIM, unsigned int COMP> void CreateType() { vtkImageData* dummyVTKImageData = vtkImageData::New(); if (true) { typedef itk::Vector< char, COMP > PixelType; typedef itk::Image< PixelType, DIM > ImageType; vtkITKFilter_CreateFunctionsMacro; } if (true) { typedef itk::Vector< unsigned char, COMP > PixelType; typedef itk::Image< PixelType, DIM > ImageType; vtkITKFilter_CreateFunctionsMacro; } ... und das ganze jetzt noch 10 Mal } //step 2 template<unsigned int DIM> void FinalizeImageType() { CreateType<DIM, 1>(); CreateType<DIM, 2>(); CreateType<DIM, 3>(); } //step 1 void StartTypeGeneration() { FinalizeImageType<1>(); FinalizeImageType<2>(); FinalizeImageType<3>(); }Damit bleibt der Header schön schlank und man kann sich eine große lib erzeugen, in der alle Methoden-Varianten komplett vertreten sind.
Wie gesagt, mit Template Metaprogrammierung wie am Anfang geschrieben und von Camper so ausführlich erklärt funktioniert das nur wenn der ganze Quelltext mit im Header steht. Auf so einen Header hat natürlich kein Mensch Lust, also ist das jetzt hier besser.
Ob es einen wirkliche "eleganten" Weg dafür gibt weiß der Geier...
-
So ihr Spezialisten, es geht also doch anders und besser.
StichwortExplizite Instanziierung
Zu lesen hier:
http://msdn.microsoft.com/en-us/library/by56e477.aspxWieso soll das bei mir nicht helfen? Es hat!