Última actualización:2026-10-12
Análisis del código fuente de STL typename¶
En el código fuente subyacente de STL hay unas líneas en las que typedef se usa junto con typename; a primera vista parecen muy complejas, ¿qué significan exactamente? ¡Hoy las analizamos juntos!
template<typename _Iterator>
struct iterator_traits
{
typedef typename _Iterator::iterator_category iterator_category;
typedef typename _Iterator::value_type value_type;
typedef typename _Iterator::difference_type difference_type;
typedef typename _Iterator::pointer pointer;
typedef typename _Iterator::reference reference;
};
Usos comunes de typename¶
Primero aprendamos los usos comunes de typename:
Lo anterior es solo un programa de ejemplo; si se quisiera escribir de forma más completa una comparación de valores, habría que considerar además las versiones especializadas. Quizá pienses que sustituir typename por class en el código anterior funciona igual, ¡y en efecto! Entonces surge la duda: ¿hay alguna diferencia entre ambas formas? Tras consultar C++ Primer, se descubre que son exactamente iguales.
Ámbito de clase¶
Al acceder desde fuera de una clase a nombres definidos dentro de ella, se puede usar el operador de ámbito de clase; las llamadas con la forma MyClass::name suelen darse en tres casos: miembros de datos estáticos, funciones miembro estáticas y tipos anidados:
struct MyClass {
static int A; //静态成员
static int B(){cout<<"B()"<<endl; return 100;} //静态函数
typedef int C; //嵌套类型
struct A1 { //嵌套类型
static int s;
};
};
Al invocarlas, se puede llamar directamente:
Prueba con un ejemplo completo¶
Volquemos a un ejemplo con typename:
¿Cuál es el propósito de este código? La primera reacción de la mayoría será: el autor quiere definir un puntero iter cuyo tipo apuntado es el iterator contenido en el ámbito de clase T. Podría existir una estructura así, que contenga un tipo iterator:
La llamada sería así:
De este modo, la línea de iter queda clara: es un puntero al tipo MyIterator::iterator. Conjeturamos que es así, ¿pero lo es en realidad?
Sin embargo, ¿qué ocurre con algo como T::iterator? T es un parámetro de tipo de la plantilla y no se sabrá de qué tipo se trata hasta que la plantilla se instancie, y lo mismo cabe decir del iterator interno. Por la introducción anterior al ámbito de clase sabemos que T::iterator puede ser en realidad cualquiera de estos tres tipos:
- miembro de datos estático
- función miembro estática
- tipo anidado
El ContainsAType::iterator del ejemplo anterior es un tipo anidado, así que no hay ningún problema. Pero ¿y si fuera un miembro de datos estático? ¿Qué pasa si el tipo con el que se instancia la plantilla foo es algo como esto?
Entonces T::iterator * iter; es instanciado por el compilador como MyIterator::iterator * iter;. ¿Qué es esto? Lo primero es una variable miembro estática y no un tipo, de modo que la línea se convierte en una expresión de multiplicación; solo que aquí iter no está definido y el compilador dará un error:
typename¶
Para los nombres usados en una definición de plantilla que dependen de un parámetro de plantilla, el compilador solo considerará ese nombre como un tipo si el tipo existe en los argumentos de la instanciación, o si el nombre va precedido de la palabra clave typename. Fuera de estos dos casos, jamás se tratará como un tipo.
Por tanto, si quieres decirle directamente al compilador que T::iterator es un tipo y no una variable, basta con cualificarlo con typename:
Así el compilador puede determinar que T::iterator es un tipo sin necesidad de esperar al momento de la instanciación, con lo que se elimina la ambigüedad mencionada antes.
Análisis del código fuente¶
Volvamos al código fuente de STL
template<typename _Iterator>
struct iterator_traits
{
typedef typename _Iterator::iterator_category iterator_category;
typedef typename _Iterator::value_type value_type;
typedef typename _Iterator::difference_type difference_type;
typedef typename _Iterator::pointer pointer;
typedef typename _Iterator::reference reference;
};
Al ver lo anterior todo queda claro de inmediato: no es más que usar typename para decirle al compilador que _Iterator::iterator_category es un tipo y luego re nombrarlo con typedef; el resto es análogo.
Temas relacionados¶
- Análisis del código fuente de STL array | C++那些事
- Análisis profundo de STL string | C++那些事
- STL string preguntas de entrevista explicadas | C++那些事
- Análisis del código fuente de STL deque | C++那些事
- STL optimización de clase base vacía EBO | C++那些事
- STL implementación de una tabla hash escrita a mano | C++那些事
- STL hashtable tabla hash | C++那些事
- Análisis del código fuente de los iteradores STL | C++那些事
- Análisis del código fuente de STL list | C++那些事
- STL map y multimap | C++那些事