Ein Kollege von mir erzählte mir von einem kleinen Stück Design, das er mit seinem Team benutzt hatte, das meine Gedanken zum Kochen brachte. Es ist eine Art von Traits Klasse, die sie in einer extrem entkoppelten Art und Weise spezialisieren können.Nicht definierte Vorlagenmethoden Trick?
Ich hatte eine harte Zeit zu verstehen, wie es möglicherweise funktionieren könnte, und ich bin immer noch unsicher über die Idee, die ich habe, also dachte ich, ich würde hier um Hilfe bitten.
Wir sprechen hier g ++, speziell die Versionen 3.4.2 und 4.3.2 (es scheint mit beiden zu funktionieren).
Die Idee ist ganz einfach:
1- die Schnittstelle definieren
// interface.h
template <class T>
struct Interface
{
void foo(); // the method is not implemented, it could not work if it was
};
//
// I do not think it is necessary
// but they prefer free-standing methods with templates
// because of the automatic argument deduction
//
template <class T>
void foo(Interface<T>& interface) { interface.foo(); }
2- eine Klasse definieren, und in der Quelldatei für diese Klasse die Schnittstelle spezialisiert sind (Definition ihrer Methoden)
// special.h
class Special {};
// special.cpp
#include "interface.h"
#include "special.h"
//
// Note that this specialization is not visible outside of this translation unit
//
template <>
struct Interface<Special>
{
void foo() { std::cout << "Special" << std::endl; }
};
3- nutzen zu können, ist es zu einfach:
// main.cpp
#include "interface.h"
class Special; // yes, it only costs a forward declaration
// which helps much in term of dependencies
int main(int argc, char* argv[])
{
Interface<Special> special;
foo(special);
return 0;
};
Es ist ein undefiniertes Symbol, wenn keine Übersetzungseinheit eine Spezialisierung von Interface
für Special
definiert hat.
Jetzt hätte ich gedacht, dass dies das Schlüsselwort export
erfordern würde, das meines Wissens nie in g ++ implementiert wurde (und nur einmal in einem C++ - Compiler implementiert wurde, wobei seine Autoren niemanden dazu ermahnten, angesichts der Zeit und des Aufwands es nahm sie).
Ich vermute, es hat etwas mit dem Linker Lösung der Vorlagen Methoden zu tun ...
- Haben Sie jemals etwas Derartiges schon einmal getroffen?
- Entspricht es dem Standard oder glauben Sie, es ist ein glücklicher Zufall, dass es funktioniert?
Ich muss ich durch das Konstrukt bin ganz verwirrt zugeben ...
Also wenn ich richtig verstehe, würde es ausreichen in "special.h" "interface.h" einzuschließen und die Template-Spezialisierung 'template <> struct Interface;' zu deklarieren und dann in "main.cpp" einzuschließen "special.h", um das Programm wohlgeformt zu machen, obwohl die Definition der 'Interface :: foo' Methode nie erscheinen würde? –
@Matthieu, genau!So können Sie das Elend lösen –
Wenn ich das richtig lese, bedeutet das, dass jedes Programm (mehrere Übersetzungseinheiten) eine explizite Spezialisierung einer Vorlage für einen gegebenen Satz von Parametern enthält, aber in einer anderen Übersetzungseinheit wird die implizite Spezialisierung verwendet Derselbe Parametersatz ist eine ODR-Verletzung, die der Compiler nicht benötigt - und wahrscheinlich nicht kann -, um eine Diagnose zu erstellen. Das ist ziemlich gruselig und ein weiterer guter Grund, immer Teilspezialisierungen mit der primären Vorlage immer wenn möglich zu platzieren. – Stewart