Type
Objetos , referencias , funciones incluyendo especializaciones de plantillas de función , y expresiones tienen una propiedad llamada tipo , que tanto restringe las operaciones permitidas para esas entidades como proporciona significado semántico a las secuencias genéricas de bits.
Contenidos |
Clasificación de tipos
El sistema de tipos de C++ consta de los siguientes tipos:
- tipos fundamentales (ver también std::is_fundamental ):
-
- el tipo void (ver también std::is_void );
|
(desde C++11) |
-
- tipos aritméticos (ver también std::is_arithmetic ):
-
- tipos integrales (incluyendo versiones calificadas cv , ver también std::is_integral , un sinónimo para tipo integral es tipo entero):
-
- el tipo bool ;
- tipos de caracteres:
-
- tipos de caracteres estrechos:
-
- tipos de caracteres ordinarios: char , signed char , unsigned char [1]
|
(desde C++20) |
-
-
-
-
- tipos de caracteres anchos: char16_t , char32_t , (desde C++11) wchar_t ;
- tipos enteros con signo:
-
- tipos enteros con signo estándar: signed char , short , int , long , long long ;
-
-
-
|
(since C++11) |
-
-
-
- tipos de enteros sin signo:
-
- tipos de enteros sin signo estándar: unsigned char , unsigned short , unsigned , unsigned long , unsigned long long ;
-
-
|
(desde C++11) |
-
-
- tipos de punto flotante (ver también std::is_floating_point ):
-
- tipos estándar de punto flotante: float , double , long double y sus versiones calificadas cv ;
-
|
(desde C++23) |
- tipos compuestos (consulte también std::is_compound ):
-
- tipos de referencia (ver también std::is_reference ):
-
- tipos de referencia lvalue (ver también std::is_lvalue_reference ):
-
- referencia lvalue a tipos de objeto;
- referencia lvalue a tipos de función;
|
(desde C++11) |
-
- tipos de puntero (ver también std::is_pointer ):
- tipos puntero-a-miembro (ver también std::is_member_pointer ):
-
- tipos puntero-a-dato-miembro (ver también std::is_member_object_pointer );
- tipos puntero-a-función-miembro (ver también std::is_member_function_pointer );
- tipos de arreglo (ver también std::is_array );
- tipos de función (ver también std::is_function );
- tipos de enumeración (ver también std::is_enum );
|
(desde C++11) |
-
-
- tipos no unión (ver también std::is_class );
- union types (ver también std::is_union ).
-
- ↑ signed char y unsigned char son tipos de caracteres estrechos, pero no son tipos de caracteres. En otras palabras, el conjunto de tipos de caracteres estrechos no es un subconjunto del conjunto de tipos de caracteres.
Para cada tipo no calificado-cv que no sea referencia y función, el sistema de tipos admite tres versiones adicionales calificadas-cv de ese tipo ( const , volatile , y const volatile ).
Otras categorías
Un tipo de objeto (ver también std::is_object ) es un tipo (posiblemente calificado con cv) que no es un tipo función, no es un tipo referencia, y no es void (posiblemente calificado con cv).
Los siguientes tipos se denominan colectivamente tipos escalares (ver también std::is_scalar ):
- tipos aritméticos
- tipos de enumeración
- tipos de puntero
- tipos de puntero-a-miembro
| (desde C++11) |
- versiones calificadas cv de estos tipos
Los siguientes tipos se denominan colectivamente tipos de duración implícita :
- tipos escalares
- tipos de clase de duración implícita
- tipos de arreglo
- versiones calificadas cv de estos tipos
|
Los siguientes tipos se denominan colectivamente tipos trivialmente copiables :
Los siguientes tipos se denominan colectivamente tipos de diseño estándar :
|
(desde C++11) |
| Diagrama de jerarquía de rasgos de tipo |
|---|
|
Nota: Los elementos de la imagen SVG son clickeables, pero primero debe abrir el diagrama en una nueva pestaña del navegador |
Categorías obsoletas
|
Los siguientes tipos se denominan colectivamente tipos POD (ver también std::is_pod ):
|
(obsoleto en C++20) |
|
Los siguientes tipos se denominan colectivamente tipos triviales (ver también std::is_trivial ):
|
(desde C++11)
(obsoleto en C++26) |
Tipo definido por el programa
Una especialización definida por el programa es una especialización explícita o especialización parcial que no forma parte de la biblioteca estándar de C++ y no está definida por la implementación.
Un tipo definido por el programa es uno de los siguientes tipos:
- Un tipo que no es closure (desde C++11) tipo clase o tipo enumeración que no forma parte de la biblioteca estándar de C++ y no está definido por la implementación.
|
(desde C++11) |
- Una instanciación de una especialización definida por el programa.
Nomenclatura de tipos
Un name puede declararse para referirse a un tipo mediante:
- class declaración;
- union declaración;
- enum declaración;
- typedef declaración;
- type alias declaración.
Los tipos que no tienen nombres a menudo necesitan ser referenciados en programas de C++; la sintaxis para eso se conoce como
type-id
. La sintaxis del type-id que nombra al tipo
T
es exactamente la sintaxis de una
declaración
de una variable o función de tipo
T
, omitiendo el identificador, excepto que el
decl-specifier-seq
de la gramática de declaración está restringido a
type-specifier-seq
, y que nuevos tipos pueden definirse solo si el type-id aparece en el lado derecho de una declaración de alias de tipo no plantilla.
int* p; // declaración de un puntero a int static_cast<int*>(p); // type-id es "int*" int a[3]; // declaración de un array de 3 int new int[3]; // type-id es "int[3]" (llamado new-type-id) int (*(*x[2])())[3]; // declaración de un array de 2 punteros a funciones // que retornan puntero a array de 3 int new (int (*(*[2])())[3]); // type-id es "int (*(*[2])())[3]" void f(int); // declaración de una función que toma int y retorna void std::function<void(int)> x = f; // parámetro de plantilla de tipo es un type-id "void(int)" std::function<auto(int) -> void> y = f; // igual std::vector<int> v; // declaración de un vector de int sizeof(std::vector<int>); // type-id es "std::vector<int>" struct { int x; } b; // crea un nuevo tipo y declara un objeto b de ese tipo sizeof(struct { int x; }); // error: no se pueden definir nuevos tipos en una expresión sizeof using t = struct { int x; }; // crea un nuevo tipo y declara t como un alias de ese tipo sizeof(static int); // error: especificadores de clase de almacenamiento no son parte de type-specifier-seq std::function<inline void(int)> f; // error: tampoco los especificadores de función
La parte declarator de la gramática de declaración con el nombre eliminado se denomina abstract-declarator .
Type-id puede ser utilizado en las siguientes situaciones:
- para especificar el tipo destino en expresiones de conversión ;
-
como argumentos de
sizeof,alignof,alignas,new, ytypeid; - en el lado derecho de una declaración de alias de tipo ;
- como el tipo de retorno final de una declaración de función ;
- como el argumento predeterminado de un parámetro de plantilla de tipo ;
- como el argumento de plantilla para un parámetro de plantilla de tipo ;
| (hasta C++17) |
El type-id puede utilizarse con algunas modificaciones en las siguientes situaciones:
- en la lista de parámetros de una función (cuando se omite el nombre del parámetro), type-id utiliza decl-specifier-seq en lugar de type-specifier-seq (en particular, se permiten algunos especificadores de clase de almacenamiento);
- en el nombre de una función de conversión definida por el usuario , el declarador abstracto no puede incluir operadores de función o array.
|
Esta sección está incompleta
Razón: 8.2[dcl.ambig.res] si puede resumirse de manera compacta |
|
Esta sección está incompleta
Razón: mencionar y enlazar a decltype y auto |
Especificador de tipo elaborado
Los especificadores de tipo elaborados pueden utilizarse para referirse a un nombre de clase previamente declarado (class, struct o union) o a un nombre de enumeración previamente declarado incluso si el nombre estaba oculto por una declaración de no-tipo . También pueden utilizarse para declarar nuevos nombres de clase.
Consulte elaborated type specifier para más detalles.
Tipo estático
El tipo de una expresión que resulta del análisis en tiempo de compilación del programa se conoce como el static type de la expresión. El static type no cambia mientras el programa se está ejecutando.
Tipo dinámico
Si alguna expresión glvalue se refiere a un objeto polimórfico , el tipo de su objeto más derivado se conoce como el tipo dinámico.
// dado struct B { virtual ~B() {} }; // tipo polimórfico struct D : B {}; // tipo polimórfico D d; // objeto más derivado B* ptr = &d; // el tipo estático de (*ptr) es B // el tipo dinámico de (*ptr) es D
Para las expresiones prvalue, el tipo dinámico siempre es el mismo que el tipo estático.
Tipo incompleto
Los siguientes tipos son tipos incompletos :
- el tipo void (posiblemente cv -calificado);
-
tipos de objeto incompletamente definidos
:
- tipo de clase que ha sido declarado (ej. por declaración anticipada ) pero no definido;
- arreglo de límite desconocido ;
- arreglo de elementos de tipo incompleto;
- tipo de enumeración desde el punto de declaración hasta que su tipo subyacente es determinado.
Todos los demás tipos están completos.
Cualquiera de los siguientes contextos requiere que el tipo
T
esté completo:
-
definición
o llamada a una función con tipo de retorno
To tipo de argumentoT; -
definición
de un objeto de tipo
T; -
declaración de un
miembro de datos no estático de clase
de tipo
T; -
newexpresión para un objeto de tipoTo un array cuyo tipo de elemento esT; -
conversión de lvalue a rvalue
aplicada a un glvalue de tipo
T; -
una conversión
implícita
o
explícita
al tipo
T; -
una
conversión estándar
,
dynamic_cast, ostatic_castal tipo T * o T & , excepto cuando se convierte desde la constante de puntero nulo o desde un puntero a void posiblemente calificado con cv ; -
operador de acceso a miembro de clase
aplicado a una expresión de tipo
T; -
typeid,sizeof, oalignofaplicado al tipoT; -
operador aritmético
aplicado a un puntero a
T; -
definición de una clase con clase base
T; -
asignación a un lvalue de tipo
T; -
un
manejador
de tipo
T, T & , o T * .
(En general, cuando el tamaño y diseño de
T
deben conocerse.)
Si cualquiera de estas situaciones ocurre en una unidad de traducción, la definición del tipo debe aparecer en la misma unidad de traducción. De lo contrario, no es requerida.
Un tipo de objeto incompletamente definido puede ser completado:
- Un tipo de clase (como class X ) puede considerarse incompleto en un punto de una unidad de traducción y considerarse completo más adelante; el tipo class X es el mismo tipo en ambos puntos:
struct X; // declaración de X, aún no se proporciona la definición extern X* xp; // xp es un puntero a un tipo incompleto: // la definición de X no es accesible void foo() { xp++; // incorrecto: X está incompleto } struct X { int i; }; // definición de X X x; // OK: la definición de X es accesible void bar() { xp = &x; // OK: tipo es "puntero a X" xp++; // OK: X está completo }
- El tipo declarado de un objeto array podría ser un array de tipo de clase incompleto y por lo tanto incompleto; si el tipo de clase se completa posteriormente en la unidad de traducción, el tipo array se vuelve completo; el tipo array en esos dos puntos es el mismo tipo.
-
El tipo declarado de un objeto array podría ser un array de límite desconocido y por lo tanto ser incompleto en un punto de una unidad de traducción y completo posteriormente; los tipos array en esos dos puntos ("array de límite desconocido de
T" y "array de NT") son tipos diferentes.
El tipo de un puntero o referencia a un array de límite desconocido apunta permanentemente o se refiere a un tipo incompleto. Un array de límite desconocido nombrado por una
typedef
declaración se refiere permanentemente a un tipo incompleto. En cualquier caso, el tipo array no puede ser completado:
extern int arr[]; // el tipo de arr es incompleto typedef int UNKA[]; // UNKA es un tipo incompleto UNKA* arrp; // arrp es un puntero a un tipo incompleto UNKA** arrpp; void foo() { arrp++; // error: UNKA es un tipo incompleto arrpp++; // OK: sizeof UNKA* es conocido } int arr[10]; // ahora el tipo de arr es completo void bar() { arrp = &arr; // OK: conversión de calificación (desde C++20) arrp++; // error: UNKA no puede ser completado }
Informes de defectos
Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares de C++ publicados anteriormente.
| DR | Aplicado a | Comportamiento publicado | Comportamiento correcto |
|---|---|---|---|
| CWG 328 | C++98 |
los miembros de clase de tipo incompleto no estaban prohibidos
si nunca se creaba un objeto del tipo de clase |
los miembros de datos no estáticos de clase
deben ser completos |
| CWG 977 | C++98 |
el momento en que un tipo de enumeración se vuelve
completo en su definición no estaba claro |
el tipo es completo una vez que se
determina el tipo subyacente |
| CWG 1362 | C++98 |
las conversiones definidas por el usuario al tipo
T*
o
T&
requerían
T
completo
|
no requerido |
| CWG 2006 | C++98 | los tipos void calificados cv eran tipo objeto y tipo completo | excluidos de ambas categorías |
| CWG 2448 | C++98 | solo los tipos no calificados cv podían ser tipos integrales y de punto flotante | permite tipos calificados cv |
| CWG 2630 | C++98 |
no estaba claro si una clase se considera completa fuera
de la unidad de traducción donde aparece la definición de la clase |
la clase es completa
si su definición es alcanzable en este caso |
| CWG 2643 | C++98 |
el tipo de un puntero a array de límite desconocido
no podía completarse (pero ya es completo) |
el tipo de array apuntado
no puede completarse |
| LWG 2139 | C++98 | el significado de "tipo definido por el usuario" no estaba claro |
define y usa "tipo definido por
programa" en su lugar |
| LWG 3119 | C++11 | no estaba claro si los tipos de clausura son tipos definidos por programa | aclarado |
Referencias
- Estándar C++23 (ISO/IEC 14882:2024):
-
- 6.8.2 Tipos fundamentales [basic.fundamental]
- Estándar C++20 (ISO/IEC 14882:2020):
-
- 6.8.2 Tipos fundamentales [basic.fundamental]
- Estándar C++17 (ISO/IEC 14882:2017):
-
- 6.9.1 Tipos fundamentales [basic.fundamental]
- Estándar C++14 (ISO/IEC 14882:2014):
-
- 3.9.1 Tipos fundamentales [basic.fundamental]
- Estándar C++11 (ISO/IEC 14882:2011):
-
- 3.9.1 Tipos fundamentales [basic.fundamental]
- Estándar C++98 (ISO/IEC 14882:1998):
-
- 3.9.1 Tipos fundamentales [basic.fundamental]
Véase también
| Type traits | Una interfaz basada en plantillas en tiempo de compilación para consultar las propiedades de los tipos |
|
C documentation
para
Type
|
|
Enlaces externos
| 1. | Árbol de tipos de C++0x de Howard Hinnant |