Templates parte 3

De ccppbrasil.org

Tabela de conteúdo

Templates parte 3 - Curiously Recurring Template Pattern

Continuando com o assunto templates (veja Templates parte 1 e Templates parte 2), nesta terceira parte vou descrever a técnica chamada “Curiously Recurring Template Pattern” ou CRTP.
Este nome é empregado quando a classe base deriva de outra classe cujo parâmetro template é a própria classe derivada.

Ou seja:

class derived : public base<derived>
{
..
}

Aplicação:

Em poucas palavras, esta técnica permite que a classe base acesse a classe derivada através de um cast de seu ponteiro.
A maneira mais comum da classe base acessar a classe derivada é através de funções virtuais. Com a CRTP você tem uma alternativa para conseguir um comportamento semelhante sem a necessidade do overhead da vtable.
Para exemplificar, vou começar com uma solução baseada em funções virtuais:
Por exemplo:

class base 
{
  virtual void do_on_change()
  { 
    /*default code*/ 
  }

public:
  void on_change() { do_on_change(); }
};

class derived : public base 
{
  void do_on_change() 
  {
     /*new code for do_on_change*/ 
  }
};

int main(){
  derived d;
  base & b = d;
  b.on_change();
}

O código acima mostra o comportamento básico das funções virtuais e não requer grandes explicações. Pelo exemplo a função do_on_change implementada na classe derivada é chamada pela classe base.

Prosseguindo, agora um exemplo equivalente utilizando a técnica CRTP.

template<class T>
class base 
{
public:
  void on_change() 
  {
      T * p = static_cast<T*> this;
      p->do_on_change();
  }
};

class derived : public base<derived>
{
  public:
   void do_on_change() 
   {
      ... 
   }
};

int main()
{
  derived d;
  base<derived> & b = d;
  b.do_change();
}

A chamada da função do_on_change() da classe derivada é feita diretamente pelo ponteiro “this” da classe base convertido para classe derivada.
Mas isso não é gambiarra? Não. Apesar de parecer um pouco estranho a validade do cast é garantida justamente pela herança que foi criada.

Uma das vantagens do uso desta técnica sobre a solução com funções virtuais é justamente não precisar do overhead da vtable e das chamadas de funções virtuais.
Outra vantagem é que você pode acessar variáveis e enumerações da classe derivada e não apenas funções como é o caso da solução com funções virtuais.

E o “curious” do nome vem da onde?
Vem do fato da classe precisar dela mesma para existir. Isto só é possível pois os templates só existem após instanciados. (Não confunda instância de template com instância de objeto)


Conclusão

A solução não substitue as funções virtuais de forma alguma, e não é equivalente em todas as situações.
O uso mais geral da técnica depende da criatividade de cada um, mas é alternativa leve e interessante para muitos problemas.
Vários exemplos desta técnica podem ser encontrados na ATL e WTL.


Links:

Uma exemplo de aplicação da técnica
http://www.angelikalanger.com/Articles/Cuj/05.Manipulators/Manipulators.html


Veja também:

Templates parte 1
Templates parte 2


http://en.wikipedia.org/wiki/Curiously_Recurring_Template_Pattern

Ferramentas pessoais