La especialización parcial de plantillas es un mecanismo del lenguaje de programación C++ diseñado para especializar clases de plantillas genéricas para tareas específicas o para un subconjunto específico de sus tipos de datos parametrizados [1] . Según el científico estadounidense y creador de C++ B. Stroustrup , la especialización de plantillas es un medio eficaz para evitar el crecimiento descontrolado de los volúmenes de código con el uso activo de herramientas de clase de plantilla, incluso cuando se desarrollan proyectos de software de tamaño moderado. Esto se debe a que no permite generar réplicas de código redundantes para cada tipo de dato específico, reemplazándolas por fragmentos de código más generalizados y, además, reduciendo el tiempo de compilación y enlace del producto final [2] .
En C++, la especialización explícita de un tipo de datos parametrizados (plantilla) se lleva a cabo mediante la creación de una clase de plantilla adicional en la que los parámetros de entrada de la clase principal se redefinen total o parcialmente mediante tipos de datos específicos [1] [3] .
La sintaxis para tal anulación es la siguiente [4] :
plantilla < lista de parámetros de entrada de clase de plantilla > clase | estructura | union class_name < lista de argumentos de clase de plantilla > _ _Por ejemplo [1] :
// plantilla de clase principal < ventana de nombre de tipo , controlador de nombre de tipo > widget de clase { /* ... implementación de la clase Widget parametrizada para cualquier tipo de ventana y cualquier controlador de eventos del controlador */ }; // especialización explícita de la plantilla de clase primaria <> widget de clase < ventana de diálogo , controlador de diálogo > { /* ... implementación de la clase Widget para trabajar con el cuadro de diálogo DialogWindow y el controlador de eventos del cuadro de diálogo DialogController */ };Se observa que las definiciones de tipos de datos contenidas en una clase primaria nunca se utilizan para instanciar los miembros de su especialización parcial. Sin embargo, la implementación de código de versiones especializadas de la clase primaria no tiene nada que ver con esto y puede contener un conjunto de miembros que no tienen nada que ver con los miembros de la clase primaria [4] .
En la etapa de generación de código, el compilador, al buscar una plantilla adecuada, ordena parcialmente las variantes de la especialización de clase primaria que tiene disponibles y selecciona la más adecuada de ellas. Si no hay ninguno, el compilador genera un mensaje de error [4] .
Una especialización parcial de una plantilla de clase se define como alguna configuración de los parámetros de una clase primaria que sirve como argumento para la implementación especializada. Un ejemplo de tal especialización es cualquier clase de contenedor implementada para almacenar objetos de puntero [2] [5] :
// plantilla de clase primaria < nombre de tipo T > clase vectorial { /* ... implementación de clase contenedora para objetos de tipo T... */ }; // especialización parcial de la clase primaria para almacenar plantilla de punteros < typename T > clase Vector < T * > { /* ... implementación de clase contenedora para punteros a objetos de tipo T... */ };En este caso, el argumento del parámetro de plantilla no es una expresión que se pasa a la plantilla como argumento, sino que se deriva de la construcción del argumento en función de la plantilla de clase primaria declarada [2] .
No se permite la especialización parcial de métodos individuales de una clase de plantilla parametrizada [1] , y no se permite la especialización parcial para usar parámetros predeterminados [5] .
El uso flexible de la especialización de plantilla parcial le permite realizar de manera eficiente algunos tipos de cálculos no triviales. Por ejemplo, una composición de clases bastante simple puede ayudar a calcular la estructura (número de dimensiones) de una matriz multidimensional con elementos de un tipo previamente desconocido [5] :
// plantilla de clase primaria < clase T > struct RankOfArray { static const int value = 0 ; }; // plantilla de clase parcialmente especializada recurrente < class T , int N > struct RankOfArray < T [ N ] > { static const int value = 1 + RankOfArray < T >:: value ; };