Patrón de plantilla curiosamente recurrente


El patrón de plantilla curiosamente recurrente ( CRTP ) es un modismo en C++ en el que una clase se Xderiva de una instanciación de plantillaX de clase que se usa a sí misma como argumento de plantilla. [1] Más generalmente, se conoce como polimorfismo ligado a F , y es una forma de cuantificación ligada a F.

La técnica se formalizó en 1989 como " cuantificación limitada por F ". [2] El nombre "CRTP" fue acuñado de forma independiente por Jim Coplien en 1995, [3] quien lo había observado en algunos de los primeros códigos de plantilla de C++ , así como en ejemplos de código que Timothy Budd creó en su lenguaje multiparadigma Leda. [4] A veces se le llama "herencia al revés" [5] [6] debido a la forma en que permite que las jerarquías de clases se amplíen mediante la sustitución de diferentes clases base.

La implementación de Microsoft de CRTP en Active Template Library (ATL) fue descubierta de forma independiente, también en 1995, por Jan Falkin, quien accidentalmente derivó una clase base de una clase derivada. Christian Beaumont vio por primera vez el código de Jan e inicialmente pensó que no podría compilarse en el compilador de Microsoft disponible en ese momento. Tras la revelación de que efectivamente funcionó, Christian basó todo el diseño de ATL y la Biblioteca de plantillas de Windows (WTL) en este error. [ cita requerida ]

Algunos casos de uso de este patrón son el polimorfismo estático y otras técnicas de metaprogramación, como las descritas por Andrei Alexandrescu en Modern C++ Design . [7] También ocupa un lugar destacado en la implementación de C++ del paradigma de datos, contexto e interacción . [8]

Por lo general, la plantilla de la clase base aprovechará el hecho de que los cuerpos de las funciones miembro (definiciones) no se instancian hasta mucho después de sus declaraciones, y usará miembros de la clase derivada dentro de sus propias funciones miembro, mediante el uso de una conversión ; p.ej:

En el ejemplo anterior, observe en particular que la función Base<Derived>::implementation(), aunque declarada antes de que el compilador conozca la existencia de la estructura Derived (es decir, antes de que se declare Derived), en realidad no es instanciada por el compilador hasta que lo llame un código posterior que ocurre después de la declaración de Derived (no se muestra en el ejemplo anterior), de modo que en el momento en que se crea una instancia de la función "implementación", se conoce la declaración de Derived::implementation() .