CRTP para evitar el polymorphism dynamic

¿Cómo puedo usar CRTP en C ++ para evitar la sobrecarga de las funciones de miembros virtuales?

Hay dos maneras.

El primero es especificando la interfaz estáticamente para la estructura de tipos:

template  struct base { void foo() { static_cast(this)->foo(); }; }; struct my_type : base { void foo(); // required to compile. }; struct your_type : base { void foo(); // required to compile. }; 

El segundo es evitar el uso de la expresión de referencia a base o puntero a base y hacer el cableado en tiempo de comstackción. Usando la definición anterior, puede tener funciones de plantilla que se vean así:

 template  // T is deduced at compile-time void bar(base & 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 

Por lo tanto, combinar la definición de estructura / interfaz y la deducción del tipo de tiempo de comstackción en sus funciones le permite realizar el envío estático en lugar del despacho dynamic. Esta es la esencia del polymorphism estático.

He estado buscando discusiones decentes sobre CRTP. Técnicas para C ++ de Todd Veldhuizen es un gran recurso para esto (1.3) y muchas otras técnicas avanzadas, como plantillas de expresión.

Además, descubrí que puedes leer la mayor parte del artículo original de C ++ Gems de Coplien en los libros de Google. Tal vez ese sigue siendo el caso.

Tuve que buscar el CRTP . Sin embargo, al haber hecho eso, encontré algunas cosas sobre el Polimorfismo Estático . Sospecho que esta es la respuesta a tu pregunta.

Resulta que ATL usa este patrón bastante extensamente.

Esta respuesta de Wikipedia tiene todo lo que necesitas. A saber:

 template  struct Base { void interface() { // ... static_cast(this)->implementation(); // ... } static void static_func() { // ... Derived::static_sub_func(); // ... } }; struct Derived : Base { void implementation(); static void static_sub_func(); }; 

Aunque no sé cuánto te compra esto realmente. La sobrecarga de una llamada de función virtual es (comstackdor dependiente, por supuesto):

  • Memoria: un puntero de función por función virtual
  • Tiempo de ejecución: una llamada de puntero a función

Mientras que la sobrecarga del polymorphism estático de CRTP es:

  • Memoria: duplicación de base por instanciación de plantilla
  • Runtime: una llamada de puntero a la función + lo que está haciendo static_cast