c++ - ¿Por qué la inicialización de un tipo dependiente constante en una lista de parámetros de plantilla no es permitida por el estándar?
templates c++11 (1)
(En mi humilde opinión) Las razones más comunes por las que el estándar no permite una característica específica son:
- La característica está cubierta por otro mecanismo en el lenguaje, por lo que es superfluo.
- Contradice la lógica y la implementación del lenguaje existente, lo que hace que su implementación sea potencialmente descodificante.
- Legacy: la función se dejó de lado en primer lugar y ahora hemos construido mucho sin ella que casi se olvida (ver especialización de plantilla de función parcial).
La dificultad de implementación rara vez es un factor, aunque puede tomar algo de tiempo para que las implementaciones del compilador se pongan al día con la evolución en lo "difícil".
Siempre puede ajustar su parámetro de plantilla no de tipo en otro tipo:
template < typename T1, typename T2 >
struct Demo {}; // primary template
template < typename T >
struct Demo<T, integral_constant<T, 0>> {}; // specialization
Dudo que este truco caiga en el caso 1. El caso 3 siempre es una posibilidad así que examinemos el caso 2. Para hacer esto, tenemos que saber cuáles son las reglas relacionadas que el estándar impone a las especializaciones parciales de las plantillas de clase.
14.5.5 Especializaciones parciales de plantilla de clase
Un argumento sin tipo no es especializado si es el nombre de un parámetro sin tipo. Todos los demás argumentos sin tipo son especializados. (C1)
Dentro de la lista de argumentos de una especialización parcial de plantilla de clase, se aplican las siguientes restricciones:
- Una expresión de argumento no especializada parcialmente especializada no implicará un parámetro de plantilla de la especialización parcial, excepto cuando la expresión de argumento sea un identificador simple. (C2)
- El tipo de un parámetro de plantilla correspondiente a un argumento especializado sin tipo no dependerá de un parámetro de la especialización. (C3)
Marqué los primeros tres años que consideré relevantes (el tercero es el que está en cuestión). De acuerdo con C1 en nuestro caso , tenemos un argumento especializado sin tipo, por lo que C2 debe mantenerse, sin embargo, esto
template <class T, T t> struct C {};
template <class T> struct C<T, 1>;
es en realidad
template <class T, T t> struct C {};
template <class T> struct C<T, T(1)>; // notice the value initialization
por lo tanto, el argumento no especializado parcialmente parcial T t
implica el parámetro de plantilla de la class T
especialización parcial class T
en una expresión distinta de un identificador; además, tales especializaciones están obligadas a involucrar a la class T
en una inicialización de valor que siempre será una violación de las reglas. Luego viene C3 y nos lo aclara para que no tengamos que hacer esa deducción cada vez.
Hasta ahora hemos establecido que las reglas están sincronizadas con ellas mismas, pero esto NO prueba el caso 2 (una vez que eliminamos la limitación inicial, todas las demás limitaciones relacionadas se desmoronan). Tendríamos que sumergirnos en reglas de especializaciones parciales de plantilla de clase coincidentes ; la ordenación parcial se considera fuera de alcance aquí, porque si podemos producir candidatos válidos, le corresponde al programador armar un programa bien formado (es decir, no crear usos ambiguos de las plantillas de clase).
Sección
Coincidencia de especializaciones parciales de plantilla de clase [temp.class.spec.match]
describe el proceso de "combinación de patrones" (dar o recibir) involucrado en la especialización de plantillas. La regla 1
es el flujo de trabajo general del procedimiento y las reglas posteriores son las que definen la corrección
Una especialización parcial coincide con una lista de argumentos de la plantilla real dada si los argumentos de la plantilla de la especialización parcial se pueden deducir de la lista de argumentos de la plantilla real
También se puede deducir un argumento de plantilla sin tipo a partir del valor de un argumento de plantilla real de un parámetro sin tipo de la plantilla primaria.
En un nombre de tipo que se refiere a una especialización de plantilla de clase, (por ejemplo, A), la lista de argumentos coincidirá con la lista de parámetros de plantilla de la plantilla primaria. Los argumentos de plantilla de una especialización se deducen de los argumentos de la plantilla primaria.
Estas reglas no se violan al permitir que el tipo de un parámetro de plantilla correspondiente a un argumento especializado sin tipo dependa de un parámetro de la especialización . Así que, en mi humilde opinión, no hay una razón específica por la cual no podamos tener esta característica en futuras revisiones del lenguaje: el legado es la culpa . Lamentablemente, no pude encontrar ninguna propuesta de idioma con la iniciativa de presentar esta función.
En la respuesta a esta publicación " (Parcial) especializando un parámetro de plantilla sin tipo de tipo dependiente ", dice:
El tipo de un parámetro de plantilla correspondiente a un argumento especializado sin tipo no dependerá de un parámetro de la especialización. [Ejemplo:
template <class T, T t> struct C {}; template <class T> struct C<T, 1>; // error template< int X, int (*array_ptr)[X] > class A {}; int array[5]; template< int X > class A<X,&array> { }; // error
-Final ejemplo]
Mi pregunta es por qué esta restricción está aquí? Hay al menos un caso de uso en el que veo que esta restricción interfiere con la escritura del código de limpieza. P.ej
template <typename T, T*>
struct test;
template <typename T>
struct test<T, nullptr> // or struct test<T, (T*)nullptr>
{
};
template <typename R, typename...ARGs, R(*fn)(ARGs...)>
struct test<R(ARGs...), fn>
{
};
Aunque no estoy seguro si hay otros casos que afirman que una constante basada en un tipo es un problema más allá de no tener ningún sentido.
¿Alguien tiene una razón de por qué esto es así?