c++ templates design-patterns crtp f-bounded-polymorphism

c++ - Usos prácticos para el "patrón de plantilla curiosamente recurrente"



templates design-patterns (6)

¿Cuáles son algunos usos prácticos para el " patrón de plantilla curiosamente recurrente "? El ejemplo de " clase contada " que se muestra comúnmente simplemente no es un ejemplo convincente para mí.


El CRTP se vuelve mucho menos curioso si se tiene en cuenta que el tipo de subclase que se pasa a la superclase solo se necesita en el momento de la expansión del método. Entonces todos los tipos están definidos. Solo necesita que el patrón importe el tipo de subclase simbólica en la superclase, pero es solo una declaración directa (como todos los tipos de parámetros formales formales son por definición) en lo que respecta a la superclase.

Usamos en una forma algo modificada, pasando la subclase en una estructura de tipo de rasgos a la superclase para posibilitar que la superclase devuelva objetos del tipo derivado. La aplicación es una biblioteca de cálculo geométrico (puntos, vectores, líneas, recuadros) donde toda la funcionalidad genérica se implementa en la superclase, y la subclase solo define un tipo específico: CFltPoint hereda de TGenPoint. También CFltPoint existía antes de TGenPoint, por lo que la creación de subclases era una forma natural de refactorizar esto.


En general, se utiliza para patrones similares a polimórficos en los que no es necesario poder elegir la clase derivada en tiempo de ejecución, solo en el momento de la compilación. Esto puede ahorrar la sobrecarga de la llamada de función virtual en tiempo de ejecución.


Para un uso de la biblioteca del mundo real de CRTP, mira ATL y WTL (wtl.sf.net). Se usa ampliamente allí para el polimorfismo en tiempo de compilación.


Se siente como una macro de C: aprovecha que la macro no se compila en el momento de la definición, sino en el momento del uso.

#define CALL_THE_RIGHT_FOO foo()

presentar un:

static void foo() { // do file A thing } ... CALL_THE_RIGHT_FOO ...

presentar un:

static void foo() { // do file B thing } ... CALL_THE_RIGHT_FOO ...

El patrón de uso de plantilla que está describiendo nos permite hacer "call the right foo" en la plantilla principal, posponiendo la definición de cuál es exactamente el foo correcto hasta que se cree una instancia de la plantilla. Excepto en este caso, es la distinción entre ClassA :: foo y ClassB :: foo en función del valor de T en Parent.


También es especialmente útil para mixins (me refiero a las clases heredadas para proporcionar funcionalidad) que necesitan saber en qué tipo están operando (y por lo tanto deben ser plantillas).

En C ++ efectivo , Scott Meyers proporciona como ejemplo una plantilla de clase NewHandlerSupport <T>. Esto contiene un método estático para anular el nuevo controlador para una clase en particular (de la misma manera que std :: set_new_handler lo hace para el operador predeterminado new) y un operador nuevo que usa el controlador. Para proporcionar un manejador por tipo, la clase padre necesita saber en qué tipo está actuando, por lo que debe ser una plantilla de clase. El parámetro de la plantilla es la clase hija.

No podría hacer esto sin CRTP, ya que necesita la instancia de NewHandlerSupport para crear una instancia por separado, con un miembro de datos estáticos por separado para almacenar el new_handler actual, por clase que lo usa.

Obviamente, el ejemplo completo es extremadamente no seguro para subprocesos, pero ilustra el punto.

Meyers sugiere que se podría pensar en CRTP como "Hazlo por mí". Yo diría que este es generalmente el caso para cualquier mixin, y CRTP se aplica en el caso donde se necesita una plantilla mixin en lugar de solo una clase mixin.


Enlace dinámico simulado . Evitar el costo de llamadas a funciones virtuales mientras se retienen algunos de los beneficios jerárquicos es una gran ganancia para los subsistemas donde se puede hacer en el proyecto en el que estoy trabajando actualmente.