En ocasiones he visto algunos mensajes de error realmente indescifrables escupidos gcc
al usar plantillas ... Específicamente, he tenido problemas en los que las declaraciones aparentemente correctas estaban causando errores de compilación muy extraños que desaparecieron mágicamente al prefijar la typename
palabra clave al comienzo del declaración ... (Por ejemplo, la semana pasada, estaba declarando dos iteradores como miembros de otra clase con plantilla y tuve que hacer esto) ...
¿De qué trata la historia typename
?
Respuestas:
La siguiente es la cita del libro de Josuttis:
fuente
typename
(¡aunque no todos!).La publicación BLog de Stan Lippman sugiere: -
Entonces, básicamente, Stroustrup reutilizó la palabra clave de clase sin introducir una nueva palabra clave que luego se cambia en el estándar por las siguientes razones
Como el ejemplo dado
la gramática del lenguaje se malinterpreta
T::A *aObj;
como una expresión aritmética, por lo que se introduce una nueva palabra clave llamadatypename
le indica al compilador que trate la declaración posterior como una declaración.
Por eso tenemos ambos
Puedes echar un vistazo a esta publicación , definitivamente te ayudará, solo la extraje todo lo que pude
fuente
typename
necesaria una nueva palabra clave , si podía usar la palabra clave existenteclass
para el mismo propósito?typename
se hizo necesario solucionar el problema de análisis como se describe en la respuesta de Naveen citando a Josuttis. (No creo que insertar unaclass
en este lugar hubiera funcionado). Solo después de que se aceptara la nueva palabra clave para este caso, también se permitía en las declaraciones de argumentos de plantilla (¿ o son definiciones? ), Porqueclass
siempre ha habido algo engañoso.Considera el código
Desafortunadamente, no se requiere que el compilador sea psíquico, y no sabe si T :: sometype terminará refiriéndose a un nombre de tipo o un miembro estático de T. Por lo tanto, uno usa
typename
para decirlo:fuente
En algunas situaciones donde se refiere a un miembro de los llamados dependientes tipo (que significa "dependiente del parámetro de plantilla"), el compilador no siempre puede deducir inequívocamente el significado semántico de la construcción resultante, porque no sabe qué tipo de nombre es (es decir, si se trata de un nombre de un tipo, un nombre de un miembro de datos o un nombre de otra cosa). En casos como ese, debe desambiguar la situación diciéndole explícitamente al compilador que el nombre pertenece a un nombre de tipo definido como miembro de ese tipo dependiente.
Por ejemplo
En este ejemplo, la palabra clave es
typename
necesaria para que el código se compile.Lo mismo sucede cuando desea hacer referencia a un miembro de plantilla de tipo dependiente, es decir, a un nombre que designa una plantilla. También debe ayudar al compilador utilizando la palabra clave
template
, aunque se coloca de manera diferenteEn algunos casos puede ser necesario usar ambos
(si obtuve la sintaxis correctamente).
Por supuesto, otra función de la palabra clave
typename
se utilizará en las declaraciones de parámetros de plantilla.fuente
El secreto radica en el hecho de que una plantilla puede especializarse para algunos tipos. Esto significa que también puede definir la interfaz completamente diferente para varios tipos. Por ejemplo, puedes escribir:
Uno podría preguntarse por qué es esto útil y de hecho: eso realmente parece inútil. Pero tenga en cuenta que, por ejemplo,
std::vector<bool>
elreference
tipo se ve completamente diferente al de otrosT
s. Es cierto que no cambia el tipo dereference
un tipo a algo diferente pero, sin embargo, podría suceder.Ahora, ¿qué sucede si escribe sus propias plantillas con esta
test
plantilla? Algo como estoparece estar bien para ti porque esperas que
test<T>::ptr
sea un tipo. Pero el compilador no lo sabe y, de hecho, incluso el estándar le aconseja que espere lo contrario,test<T>::ptr
no es un tipo. Para decirle al compilador qué espera, debe agregar untypename
antes. La plantilla correcta se ve asíEn pocas palabras: debe agregar
typename
antes cada vez que use un tipo anidado de una plantilla en sus plantillas. (Por supuesto, solo si se usa un parámetro de plantilla de su plantilla para esa plantilla interna).fuente
Dos usos:
template
palabra clave de argumento (en lugar declass
)typename
palabra clave le dice al compilador que un identificador es un tipo (en lugar de una variable miembro estática)fuente
Creo que todas las respuestas han mencionado que la
typename
palabra clave se usa en dos casos diferentes:a) Al declarar un parámetro de tipo de plantilla. p.ej
Que no hay diferencia entre ellos y son EXACTAMENTE iguales.
b) Antes de usar un nombre de tipo dependiente anidado para una plantilla.
El hecho de no usar
typename
conduce a errores de análisis / compilación.Lo que quiero agregar al segundo caso, como se menciona en el libro de Scot Meyers Effective C ++ , es que hay una excepción de usar
typename
antes de un nombre de tipo dependiente anidado . La excepción es que si usa el nombre de tipo dependiente anidado como una clase base o en una lista de inicialización de miembros , no debe usartypename
allí:Nota: El uso
typename
para el segundo caso (es decir, antes del nombre de tipo dependiente anidado) no es necesario desde C ++ 20.fuente
fuente