Wie kann ich CRTP in C ++ verwenden, um den Overhead virtueller Elementfunktionen zu vermeiden?
Wie kann ich CRTP in C ++ verwenden, um den Overhead virtueller Elementfunktionen zu vermeiden?
Antworten:
Es gibt zwei Möglichkeiten.
Die erste besteht darin, die Schnittstelle statisch für die Struktur der Typen anzugeben:
template <class Derived>
struct base {
void foo() {
static_cast<Derived *>(this)->foo();
};
};
struct my_type : base<my_type> {
void foo(); // required to compile.
};
struct your_type : base<your_type> {
void foo(); // required to compile.
};
Die zweite Möglichkeit besteht darin, die Verwendung der Referenz-zu-Basis- oder Zeiger-zu-Basis-Sprache zu vermeiden und die Verkabelung zur Kompilierungszeit durchzuführen. Mit der obigen Definition können Sie Vorlagenfunktionen haben, die wie folgt aussehen:
template <class T> // T is deduced at compile-time
void bar(base<T> & obj) {
obj.foo(); // will do static dispatch
}
struct not_derived_from_base { }; // notice, not derived from base
// ...
my_type my_instance;
your_type your_instance;
not_derived_from_base invalid_instance;
bar(my_instance); // will call my_instance.foo()
bar(your_instance); // will call your_instance.foo()
bar(invalid_instance); // compile error, cannot deduce correct overload
Wenn Sie also die Struktur- / Schnittstellendefinition und den Typabzug zur Kompilierungszeit in Ihren Funktionen kombinieren, können Sie statischen Versand anstelle von dynamischem Versand durchführen. Dies ist die Essenz des statischen Polymorphismus.
not_derived_from_base
weder von base
noch abgeleitet ist von base
...
Ich habe selbst nach anständigen Diskussionen über CRTP gesucht. Todd Veldhuizens Techniken für wissenschaftliches C ++ sind eine großartige Ressource für dieses (1.3) und viele andere fortgeschrittene Techniken wie Ausdrucksvorlagen.
Außerdem habe ich festgestellt, dass Sie den größten Teil des ursprünglichen C ++ Gems-Artikels von Coplien in Google-Büchern lesen können. Vielleicht ist das immer noch der Fall.
dynamic_cast
virtuelle Methoden benötigen .
Ich musste CRTP nachschlagen . Nachdem ich das getan hatte, fand ich einige Dinge über statischen Polymorphismus . Ich vermute, dass dies die Antwort auf Ihre Frage ist.
Es stellt sich heraus, dass ATL dieses Muster ziemlich häufig verwendet.
Diese Wikipedia-Antwort enthält alles, was Sie brauchen. Nämlich:
template <class Derived> struct Base
{
void interface()
{
// ...
static_cast<Derived*>(this)->implementation();
// ...
}
static void static_func()
{
// ...
Derived::static_sub_func();
// ...
}
};
struct Derived : Base<Derived>
{
void implementation();
static void static_sub_func();
};
Obwohl ich nicht weiß, wie viel dich das tatsächlich kauft. Der Overhead eines virtuellen Funktionsaufrufs ist (natürlich vom Compiler abhängig):
Während der Overhead des statischen CRTP-Polymorphismus ist: