typeid оператор
Запрашивает информацию о типе.
Используется, когда необходимо знать динамический тип полиморфного объекта, а также для идентификации статического типа.
Синтаксис
typeid ( type ) | (1) | |
typeid ( expression ) | (2) |
Выражение typeid является lvalue-выражением, которое ссылается на объект со статической длительностью хранения типа std::type_info с квалификатором const или некоторого производного от него типа.
Если определение std::type_info из стандартной библиотеки недоступно при использовании typeid, программа некорректна.
Пояснение
Если type или тип expression является типом класса или ссылкой на тип класса, этот тип класса не может быть неполным типом.
std::type_info, представляющий type. Если type является ссылочным типом, результат ссылается на объект std::type_info, представляющий версию указанного типа без cv-квалификаторов.- Если expression является lvalue(до C++11)glvalue(начиная с C++11)-выражением, идентифицирующим объект полиморфного типа (то есть класс, объявляющий или наследующий как минимум одну виртуальную функцию), выражение typeid вычисляет это выражение, а затем ссылается на объект
std::type_info, представляющий динамический тип выражения. - Если expression является выражением косвенного обращения, а его операнд при вычислении даёт значение нулевого указателя, выбрасывается исключение типа, соответствующего обработчикам типа
std::bad_typeid[1]. - В противном случае typeid не вычисляет выражение, а объект
std::type_info, который оно идентифицирует, представляет статический тип выражения. Преобразования lvalue-to-rvalue, array-to-pointer и function-to-pointer не выполняются.
| (начиная с C++17) |
Если type или тип expression имеет cv-квалификаторы, результат typeid ссылается на объект std::type_info, представляющий тип без cv-квалификаторов (то есть typeid(const T) == typeid(T)).
Если typeid применяется к объекту во время его конструирования или уничтожения (в деструкторе или конструкторе, включая список инициализаторов конструктора или инициализаторы членов по умолчанию), объект std::type_info, на который ссылается этот typeid, представляет класс, который конструируется или уничтожается, даже если он не является наиболее производным классом.
- В других контекстах вычисление такого expression приводит к неопределённому поведению.
Примечания
При применении к выражению полиморфного типа вычисление выражения typeid может приводить к накладным расходам во время выполнения (поиск в виртуальной таблице); в противном случае выражение typeid разрешается во время компиляции.
Не определено, вызывается ли деструктор объекта, на который ссылается typeid, в конце программы.
Не гарантируется, что все вычисления выражения typeid для одного и того же типа будут ссылаться на один и тот же объект std::type_info, хотя результаты сравнения будут равны, а std::type_info::hash_code этих объектов type_info будут идентичны, как и их std::type_index.
const std::type_info& ti1 = typeid(A); const std::type_info& ti2 = typeid(A); assert(&ti1 == &ti2); // not guaranteed assert(ti1 == ti2); // guaranteed assert(ti1.hash_code() == ti2.hash_code()); // guaranteed assert(std::type_index(ti1) == std::type_index(ti2)); // guaranteed
Ключевые слова
Пример
Пример вывода с использованием одной из реализаций, в которой type_info::name возвращает полные имена типов; если используется gcc или аналогичный компилятор, пропустите вывод через c++filt -t.
#include <iostream>
#include <string>
#include <typeinfo>
struct Base {}; // non-polymorphic
struct Derived : Base {};
struct Base2 { virtual void foo() {} }; // polymorphic
struct Derived2 : Base2 {};
int main()
{
int myint = 50;
std::string mystr = "string";
double *mydoubleptr = nullptr;
std::cout << "myint has type: " << typeid(myint).name() << '\n'
<< "mystr has type: " << typeid(mystr).name() << '\n'
<< "mydoubleptr has type: " << typeid(mydoubleptr).name() << '\n';
// std::cout << myint is a glvalue expression of polymorphic type; it is evaluated
const std::type_info& r1 = typeid(std::cout << myint); // side-effect: prints 50
std::cout << '\n' << "std::cout<<myint has type : " << r1.name() << '\n';
// std::printf() is not a glvalue expression of polymorphic type; NOT evaluated
const std::type_info& r2 = typeid(std::printf("%d\n", myint));
std::cout << "printf(\"%d\\n\",myint) has type : " << r2.name() << '\n';
// Non-polymorphic lvalue is a static type
Derived d1;
Base& b1 = d1;
std::cout << "reference to non-polymorphic base: " << typeid(b1).name() << '\n';
Derived2 d2;
Base2& b2 = d2;
std::cout << "reference to polymorphic base: " << typeid(b2).name() << '\n';
try
{
// dereferencing a null pointer: okay for a non-polymorphic expression
std::cout << "mydoubleptr points to " << typeid(*mydoubleptr).name() << '\n';
// dereferencing a null pointer: not okay for a polymorphic lvalue
Derived2* bad_ptr = nullptr;
std::cout << "bad_ptr points to... ";
std::cout << typeid(*bad_ptr).name() << '\n';
}
catch (const std::bad_typeid& e)
{
std::cout << " caught " << e.what() << '\n';
}
}
Возможный вывод:
======== output from Clang ========
myint has type: i
mystr has type: NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE
mydoubleptr has type: Pd
50
std::cout<<myint has type : NSt3__113basic_ostreamIcNS_11char_traitsIcEEEE
printf("%d\n",myint) has type : i
reference to non-polymorphic base: 4Base
reference to polymorphic base: 8Derived2
mydoubleptr points to d
bad_ptr points to... caught std::bad_typeid
======== output from MSVC ========
myint has type: int
mystr has type: class std::basic_string<char,struct std::char_traits<char>,⮠
class std::allocator<char> >
mydoubleptr has type: double * __ptr64
50
std::cout<<myint has type : class std::basic_ostream<char,struct std::char_traits<char> >
printf("%d\n",myint) has type : int
reference to non-polymorphic base: struct Base
reference to polymorphic base: struct Derived2
mydoubleptr points to double
bad_ptr points to... caught Attempted a typeid of nullptr pointer!
Отчёты об ошибках
Следующие отчёты об ошибках, изменяющие поведение, были ретроактивно применены к ранее опубликованным стандартам C++.
| DR | Применяется к | Опубликованное поведение | Корректное поведение |
|---|---|---|---|
| CWG 492 | C++98 | при применении typeid к ссылке на cv-квалифицированный тип результат представлял указанный тип | результат представляет указанный тип без cv-квалификаторов |
| CWG 1416 | C++98 | формулировка относительно cv-квалификации верхнего уровня могла быть неверно истолкована | формулировка улучшена |
| CWG 1431 | C++98 |
typeid мог выбрасывать только std::bad_typeid | разрешено выбрасывать совместимые производные классы |
| CWG 1954 | C++98 | не было ясно, можно ли проверять разыменование нулевого указателя во вложенных выражениях expression | проверка выполняется только на верхнем уровне |
См. также
| содержит информацию о типе; класс, возвращаемый оператором typeid (класс) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/language/typeid