template plantillas matriz ejemplos clase c++ templates overloading template-specialization language-lawyer

matriz - ejemplos de plantillas en c++



¿Por qué no es posible sobrecargar las plantillas de clase? (3)

La lectura de esta pregunta me hizo preguntarme: ¿existe alguna razón técnica para rechazar las sobrecargas de plantillas de clase?

Sobrecargando, me refiero a tener varias plantillas con los mismos nombres, pero diferentes parámetros, por ejemplo

template <typename T> struct Foo {}; template <typename T1, typename T2> struct Foo {}; template <unsigned int N> struct Foo {};

El compilador se las arregla para manejar funciones sobrecargadas y plantillas de funciones, ¿no sería posible aplicar las mismas técnicas (por ejemplo, mangle) a las plantillas de clase?

Al principio, pensé que tal vez eso causaría algunos problemas de ambigüedad al tomar el identificador de plantilla solo, pero el único momento en que esto puede pasar es pasándolo como un argumento de plantilla de plantilla, para que el tipo de parámetro pueda usarse para elegir el apropiado sobrecarga:

template <template <typename> class T> void A {}; template <template <unsigned int> class T> void B {}; A<Foo> a; // resolves to Foo<T> B<Foo> b; // resolves to Foo<N>

¿Crees que tal característica podría ser útil? ¿Hay algunas razones "buenas" (es decir, técnicas) por las cuales esto no es posible en el C ++ actual?


Esto ha existido desde hace un tiempo, pero todavía encontré esta publicación cuando busqué. Gracias a @ log0 por darme un buen comienzo. Aquí hay una solución que evita la necesidad de proporcionar una especialización de plantilla para todas las enumeraciones posibles. Hace una suposición: que puede definir cada expansión de plantilla en términos de sí misma y sus clases base. (Esto se haría en FooImpl continuación):

template <typename... T> struct Foo; template<typename T> struct Foo<T> { /* implementation of base class goes here*/}; template <typename C, typename Base> struct FooImpl : public Base { /* implementation of derived class goes here */}; template<typename C, typename... Bases> struct Foo<C, Bases...> : FooImpl<C, Foo<Bases...> > { /*NO IMPLEMENTATION HERE */};

El uso de FooImpl rompe la recursión ambigua que de otro modo resultaría. Esto luego permite declaraciones como las siguientes:

Foo<int> foo_int; Foo<int, double> foo_int_double; Foo<int, float, double> foo_int_float_double;

Quizás así es como lo hace STL ahora?


La Sección 12.5 de Plantillas, la Guía completa ( Amazon ) contiene esta cita:

Puede legítimamente preguntarse por qué solo las plantillas de clase pueden ser parcialmente especializadas. Las razones son en su mayoría históricas. Probablemente sea posible definir el mismo mecanismo para las plantillas de funciones (ver Capítulo 13).

De alguna manera, el efecto de las plantillas de función de sobrecarga es similar, pero también hay algunas diferencias sutiles. Estas diferencias se relacionan principalmente con el hecho de que la plantilla primaria debe buscarse cuando se encuentra un uso. Las especializaciones se consideran solo después, para determinar qué implementación se debe usar.

Por el contrario, todas las plantillas de funciones sobrecargadas deben ponerse en un conjunto de sobrecarga buscándolas, y pueden provenir de diferentes espacios de nombres o clases. Esto aumenta la probabilidad de sobrecargar involuntariamente el nombre de una plantilla.

Por el contrario, también es imaginable permitir una forma de sobrecarga de plantillas de clase. Aquí hay un ejemplo:

// invalid overloading of class templates template<typename T1, typename T2> class Pair; template<int N1, int N2> class Pair;

Sin embargo, no parece haber una necesidad urgente de tal mecanismo.

Además, el Diseño y Evolución de C ++ ( Amazon ) contiene esta cita en la sección 15.10.3

Por lo tanto, concluí que necesitábamos un mecanismo para "plantillas especializadas. Esto se podía hacer aceptando una sobrecarga general o mediante un mecanismo más específico. Elegí un mecanismo específico porque pensé que estaba abordando principalmente irregularidades causadas por irregularidades en C y porque las sugerencias de sobrecarga invariablemente crea un aullido de protestas. Intenté ser cauteloso y conservador, ahora lo considero un error . La especialización, como se definió originalmente, era una forma restringida y anómala de sobrecarga que encajaba mal con el resto del lenguaje.

Negrita énfasis mío. Interpreto esto como diciendo que la resolución de sobrecarga de función es más difícil de implementar (y corregir por los usuarios) que la especialización de clase. Probablemente no haya obstáculos técnicos reales (similares para la especialización parcial de la plantilla de función) sino un accidente histórico.


No puede "sobrecargar" el parámetro de tipo, el argumento sin tipo y el parámetro de plantilla de plantilla, pero puede especializar la plantilla variadic:

template <typename... T> struct Foo; template <typename T1> struct Foo<T1> {}; template <typename T1, typename T2> struct Foo<T1,T2> {};