Come posso utilizzare CRTP in C ++ per evitare il sovraccarico delle funzioni membro virtuali?
Come posso utilizzare CRTP in C ++ per evitare il sovraccarico delle funzioni membro virtuali?
Risposte:
Ci sono due modi.
Il primo consiste nello specificare staticamente l'interfaccia per la struttura dei tipi:
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.
};
Il secondo consiste nell'evitare l'uso dell'idioma riferimento a base o puntatore a base ed eseguire il cablaggio in fase di compilazione. Utilizzando la definizione di cui sopra, puoi avere funzioni del modello simili a queste:
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
Quindi combinare la definizione della struttura / interfaccia e la deduzione del tipo in fase di compilazione nelle funzioni consente di eseguire l'invio statico invece di quello dinamico. Questa è l'essenza del polimorfismo statico.
not_derived_from_base
non è derivato da base
, né è derivato da base
...
Ho cercato io stesso discussioni decenti su CRTP. Todd Veldhuizen's Techniques for Scientific C ++ è una grande risorsa per questa (1.3) e molte altre tecniche avanzate come i modelli di espressione.
Inoltre, ho scoperto che potresti leggere la maggior parte dell'articolo C ++ Gems originale di Coplien su Google Books. Forse è ancora così.
dynamic_cast
o metodi virtuali.
Ho dovuto cercare CRTP . Dopo averlo fatto, tuttavia, ho trovato alcune cose sul polimorfismo statico . Sospetto che questa sia la risposta alla tua domanda.
Si scopre che ATL utilizza questo modello in modo abbastanza estensivo.
Questa risposta di Wikipedia ha tutto ciò di cui hai bisogno. Vale a dire:
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();
};
Anche se non so quanto ti compri effettivamente. L'overhead di una chiamata di funzione virtuale è (dipendente dal compilatore, ovviamente):
Mentre il sovraccarico del polimorfismo statico CRTP è: