Articulo de referencia

tipo nombre

typename [ 1 ] [ 2 ] es una palabra clave en el lenguaje de programación C++ que se usa al escribir plantillas . Se usa para especificar que un nombre dependiente en una definic...

typename [ 1 ] [ 2 ] es una palabra clave en el lenguaje de programación C++ que se usa al escribir plantillas . Se usa para especificar que un nombre dependiente en una definición o declaración de plantilla es un tipo. [ 3 ] [ 4 ] En los compiladores C++ originales antes de que se completara el primer estándar ISO, lapalabra clave no formaba parte del lenguaje C++ y Bjarne Stroustrup usó lapalabra clave para los argumentos de plantilla en su lugar. Si bienahora es la palabra clave preferida, el código fuente antiguo todavía puede usar lapalabra clave en su lugar (por ejemplo, vea la diferencia en los ejemplos de código fuente entre The Design and Evolution of C++ de Bjarne Stroustrup publicado en 1994 y los ejemplos de código fuente en The C++ Programming Language: Fourth Edition de Bjarne Stroustrup publicado en 2013).typenameclasstypenameclass

Un sinónimo para classen parámetros de plantilla

En la característica de programación genérica de C++ conocida como " plantillas ", typenamese puede utilizar para introducir un parámetro de plantilla : [ 3 ] [ 4 ]

// Define una función genérica que devuelve el mayor de sus dos argumentos template < typename T > [[ nodiscard ]] const T & max ( const T & x , const T & y ) noexcept { return y < x ? x : y ; }

Una palabra clave alternativa y semánticamente equivalente en este escenario es " class":

// Define una función genérica que devuelve el mayor de sus dos argumentos template < class T > [[ nodiscard ]] const T & max ( const T & x , const T & y ) noexcept { return y < x ? x : y ; }

Cuando se utilizan conceptos , un medio para restringir el tipo genérico para que cumpla con un conjunto de reglas, el nombre del concepto reemplaza la palabra clave typename.

importar std ;usando std :: derivated_from ; usando std :: vector ;clase Jugador { // ... };// Se requiere que T sea un tipo cuyo límite superior de herencia sea Player, // bloqueando cualquier tipo que no herede de Player template < derived_from < Player > T > void processListOfPlayers ( const vector < T >& players ) { // ... }

Un método para indicar que un nombre dependiente es un tipo

Considere este código no válido: [ 5 ]

template < typename T > void foo ( const T & t ) { // declara un puntero a un objeto de tipo T::bar T :: Bar * p ; // error (ver texto) }struct UsesBar { using Bar = int ; };int main () { UsesBar x ; foo ( x ); }

Este código parece que debería compilar, pero es incorrecto porque el compilador no sabe si T::Bares un tipo o un valor. La razón por la que no lo sabe es que T::Bares un "nombre dependiente de parámetro de plantilla", o "nombre dependiente" para abreviar, que entonces podría representar cualquier cosa llamada " Bar" dentro de un tipo pasado a foo(), que podría incluir typedefs , enums , variables, etc.

Para resolver esta ambigüedad, el estándar del lenguaje C++ declara:

Se supone que un nombre utilizado en una declaración o definición de plantilla y que depende de un parámetro de plantilla no nombra un tipo a menos que la búsqueda de nombres aplicable encuentre un nombre de tipo o el nombre esté calificado por la palabra clave typename.

En resumen, si el compilador no puede determinar si un nombre dependiente es un valor o un tipo, asumirá que es un valor.

En nuestro ejemplo, donde T::Bares el nombre dependiente, eso significa que en lugar de declarar un puntero a T::Barllamado p, la línea

T :: Barra * p ;

En su lugar, multiplicará el "valor" T::Barpor p(que no se encuentra por ninguna parte) y descartará el resultado. El hecho de que en UsesBarla dependencia Barsea de hecho un tipo no ayuda, ya que foo()podría compilarse mucho antes de UsesBarque se vea. Además, si también hay una clase como:

struct HoldsBar { int Bar ; };

Entonces, el compilador estaría obligado a interpretar la T::Barentrada foo()como un acceso a un miembro de datos HoldsBar::Baral instanciarlo. Pero como Barno es un miembro de datos estático, marcará un error.

La solución a este problema es indicarle explícitamente al compilador que, T::Barde hecho, es un tipo. Para ello, typenamese utiliza la palabra clave: [ 3 ] [ 4 ]

template < typename T > void foo ( const T & t ) { // declara un puntero a un objeto de tipo T::Bar typename T :: Bar * p ; }

Ahora el compilador sabe con certeza que T::Barse trata de un tipo y creará correctamente pun puntero a un objeto de ese tipo.

En C++20typename , se redujo el uso requerido de la palabra clave. [ 6 ]

Véase también

Referencias

  1. ^ Al Stevens (abril de 2003). "C++ poco documentado". Diario del Dr. Dobb . págs. 72-76 . 
  2. TL Veldhuizen (2013). "Las plantillas de C++ se están completando" (PDF) .
  3. 1 2 3 "La palabra clave typename (solo C++)" . IBM . Consultado el 23 de agosto de 2013 .
  4. 1 2 3 "MSDN - typename" . MSDN . Consultado el 23 de agosto de 2013 .
  5. "Búsqueda de nombres dependientes para plantillas de C++" . 6 de febrero de 2012.
  6. Nina Ranns; Daveed Vandevoorde. "¡Abajo con el nombre de tipo!" . Archivado del original el 22 de abril de 2018. Recuperado el 18 de mayo de 2019 .