Operador typeid
Consulta información de un tipo.
Usado donde el tipo dinámico de un objeto polimórfico debe conocerse y para identificación de tipos estáticos.
Contenido |
[editar] Sintaxis
typeid( tipo )
|
(1) | ||||||||
typeid( expresión )
|
(2) | ||||||||
El archivo de encabezado <typeinfo> se debe incluir antes de usar typeid
(si no se incluye el archivo de encabezado, cada uso de la palabra reservada typeid
hace que el programa este mal formado).
La expresión typeid es una expresión lvalue que se refiere a un objeto con duración de almacenamiento estática, de tipo polimórfico const std::type_info o alguno derivado del mismo.
[editar] Explicación
typeid
evalúa la expresión y luego refiere al objeto std::type_info que representa el tipo dinámico de la expresión. Si la expresión glvalue se obtiene aplicando el operado unario * al puntero y el puntero tiene un valor puntero nulo, se lanza una excepción de tipo std::bad_typeid o un tipo derivado de std::bad_typeid .typeid
no evalúa la expresión, y el objeto std::type_info identifica el tipo estático de la expresión. No se realiza coneversiones de lvalue a rvalue, matriz a puntero, o función a puntero. La materialización temporal, sin embargo, se realiza para argumentos prvalue: typeid determina el tipo del objeto resultado. (desde C++17)En todos los casos, los calificadores constante/volátil se ignoran por parte de typeid (es decir, typeid(T) == typeid(const T))
Si el operando de typeid
es un tipo clase o referencia a tipo clase, entonces este tipo clase no debe ser un tipo incompleto.
Si se usa typeid
en un objeto en construcción o destrucción (en un destructor o constructor, incluyendo lista incializadora del constructor o incializadores de miembro por defecto), entonces el objeto std::type_info al que hace referencia este typeid
representa la clase que se está construyendo o destruyendo incluso si no es la clase más derivada.
[editar] Palabra reservada
[editar] Notas
Cuando se aplica a una expresión de tipo polimórfico, la evaluación de la expresión typeid puede implicar mayor tiempo de ejecución (búsqueda en una tabla virtual), en otro caso la expresión typeid se resuelve en tiempo de compilación.
No se especifica si el destructor para el objeto al que hace referencia typeid
se ejecuta al final del programa.
No se garantiza que la misma instancia de std::type_info será referida por todas las evaluaciones de la expresión typeid sobre el mismo tipo, aunque std::type_info::hash_code de esos objetos type_info serían idénticos, como también su std::type_index.
const std::type_info& ti1 = typeid(A); const std::type_info& ti2 = typeid(A); assert(&ti1 == &ti2); // no garantizado assert(ti1.hash_code() == ti2.hash_code()); // garantizado assert(std::type_index(ti1) == std::type_index(ti2)); // garantizado
[editar] Ejemplo
El ejemplo muestra la salida utilizando implementaciones donde type_info::name devuelve los nombres completos del tipo; filre a través de c++filt -t si usa gcc o similar.
#include <iostream> #include <string> #include <typeinfo> struct Base {}; // no polimórfico struct Derived : Base {}; struct Base2 { virtual void foo() {} }; // polimórfico struct Derived2 : Base2 {}; int main() { int myint = 50; std::string mystr = "string"; double *mydoubleptr = nullptr; std::cout << "myint tiene tipo: " << typeid(myint).name() << '\n' << "mystr tiene tipo: " << typeid(mystr).name() << '\n' << "mydoubleptr tiene tipo: " << typeid(mydoubleptr).name() << '\n'; // “std::cout << myint” es una expresión glvalue de tipo polimórfico; se evalúa const std::type_info& r1 = typeid(std::cout << myint); std::cout << '\n' << "std::cout<<myint tiene tipo: " << r1.name() << '\n'; // std::printf() no es una expresión glvalue de tipo polimórfico; no se evalúa const std::type_info& r2 = typeid(std::printf("%d\n", myint)); std::cout << "printf(\"%d\\n\",myint) tiene tipo: " << r2.name() << '\n'; // Un lvalue no polimórfico es un tipo estático Derived d1; Base& b1 = d1; std::cout << "referencia a base no polimórfica: " << typeid(b1).name() << '\n'; Derived2 d2; Base2& b2 = d2; std::cout << "referencia a base polimórfica: " << typeid(b2).name() << '\n'; try { // desreferenciación de un puntero nulo: correcto para una expresión no polimórfica std::cout << "mydoubleptr apunta a " << typeid(*mydoubleptr).name() << '\n'; // desreferenciación de un puntero nulo: no correcto para un lvalue polimórfico Derived2* bad_ptr = nullptr; std::cout << "bad_ptr apunta a... "; std::cout << typeid(*bad_ptr).name() << '\n'; } catch (const std::bad_typeid& e) { std::cout << " caught " << e.what() << '\n'; } }
Posible salida:
myint tiene tipo: int mystr tiene tipo: std::basic_string<char, std::char_traits<char>, std::allocator<char> > mydoubleptr tiene tipo: double* “std::cout<<myint” tiene tipo : std::basic_ostream<char, std::char_traits<char> > printf("%d\n",myint) tiene tipo : int referencia a base no polimórfica: Base referencia a base polimórfica: Derived2 mydoubleptr apunta a double bad_ptr apunta a... caught std::bad_typeid