Como posso usar CRTP em C ++ para evitar a sobrecarga de funções de membro virtual?
Como posso usar CRTP em C ++ para evitar a sobrecarga de funções de membro virtual?
Respostas:
Existem duas maneiras.
A primeira é especificando a interface estaticamente para a estrutura de tipos:
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.
};
A segunda é evitar o uso do idioma referência à base ou ponteiro para base e fazer a fiação em tempo de compilação. Usando a definição acima, você pode ter funções de modelo semelhantes a estas:
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
Portanto, combinar a definição de estrutura / interface e a dedução de tipo de tempo de compilação em suas funções permite que você faça despacho estático em vez de despacho dinâmico. Esta é a essência do polimorfismo estático.
not_derived_from_base
não é derivado de base
, nem é derivado de base
...
Tenho procurado discussões decentes sobre o CRTP. O Techniques for Scientific C ++ de Todd Veldhuizen é um grande recurso para este (1.3) e muitas outras técnicas avançadas, como modelos de expressão.
Além disso, descobri que você pode ler a maior parte do artigo C ++ Gems original de Coplien nos livros do Google. Talvez ainda seja o caso.
dynamic_cast
de métodos virtuais.
Eu tive que procurar CRTP . Tendo feito isso, no entanto, descobri algumas coisas sobre polimorfismo estático . Suspeito que esta seja a resposta à sua pergunta.
Acontece que o ATL usa esse padrão amplamente.
Esta resposta da Wikipedia tem tudo que você precisa. Nomeadamente:
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();
};
Embora eu não saiba quanto isso realmente te compra. A sobrecarga de uma chamada de função virtual é (dependente do compilador, é claro):
Embora a sobrecarga do polimorfismo estático CRTP seja: