typeid
operator
Interroge les informations d'un type.
Utilisé lorsque le dynamic type d'un polymorphic object doit être connu et pour l'identification de type statique.
Table des matières |
Syntaxe
typeid (
type
)
|
(1) | ||||||||
typeid (
expression
)
|
(2) | ||||||||
L'expression typeid est une expression lvalue qui fait référence à un objet ayant une durée de stockage statique , de la version qualifiée const du type polymorphe std::type_info ou d'un type qui en dérive.
Si la définition de la bibliothèque standard de std::type_info n'est pas visible lors de l'utilisation de typeid , le programme est mal formé.
Explication
Si type ou le type de expression est un type classe ou une référence à un type classe, alors ce type classe ne peut pas être un type incomplet .
- Si expression est un lvalue (jusqu'en C++11) un glvalue (depuis C++11) qui identifie un objet de type polymorphe (c'est-à-dire une classe qui déclare ou hérite d'au moins une fonction virtuelle ), l'expression typeid évalue l'expression puis fait référence à l'objet std::type_info qui représente le type dynamique de l'expression.
-
- Si expression est une expression d'indirection et que son opérande évalue une valeur de pointeur nul , une exception du type correspondant aux gestionnaires de type std::bad_typeid est levée [1] .
- Sinon, typeid n' évalue pas l'expression , et l'objet std::type_info qu'il identifie représente le type statique de l'expression. Les conversions lvalue-vers-rvalue, tableau-vers-pointeur ou fonction-vers-pointeur ne sont pas effectuées.
|
(depuis C++17) |
Si type ou le type de expression est qualifié cv, le résultat de typeid fait référence à un objet std::type_info représentant le type non qualifié cv (c'est-à-dire, typeid ( const T ) == typeid ( T ) ).
Si typeid est utilisé sur un objet en cours de construction ou de destruction (dans un destructeur ou dans un constructeur, y compris la liste d'initialisation du constructeur ou les initialisateurs par défaut des membres ), alors l'objet std::type_info référencé par ce typeid représente la classe en cours de construction ou de destruction, même s'il ne s'agit pas de la classe la plus dérivée.
- ↑ Dans d'autres contextes, l'évaluation d'une telle expression entraîne un comportement indéfini.
Notes
Lorsqu'il est appliqué à une expression de type polymorphe, l'évaluation d'une expression typeid peut impliquer un coût d'exécution (une consultation de table virtuelle), sinon l'expression typeid est résolue au moment de la compilation.
Il n'est pas spécifié si le destructeur de l'objet référencé par typeid est exécuté à la fin du programme.
Il n'y a aucune garantie que le même
std::type_info
objet soit référencé par toutes les évaluations de l'expression typeid sur le même type, bien qu'elles soient comparables comme égales,
std::type_info::hash_code
de ces
type_info
objets serait identique, comme le serait leur
std::type_index
.
const std::type_info& ti1 = typeid(A); const std::type_info& ti2 = typeid(A); assert(&ti1 == &ti2); // non garanti assert(ti1 == ti2); // garanti assert(ti1.hash_code() == ti2.hash_code()); // garanti assert(std::type_index(ti1) == std::type_index(ti2)); // garanti
Mots-clés
Exemple
L'exemple montrant la sortie utilisant l'une des implémentations où type_info::name retourne les noms complets des types ; filtrer via c++filt -t si vous utilisez gcc ou similaire.
#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'; } }
Sortie possible :
======== 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!
Rapports de défauts
Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.
| DR | Appliqué à | Comportement publié | Comportement correct |
|---|---|---|---|
| CWG 492 | C++98 |
lorsque
typeid
est appliqué à une référence vers un type qualifié cv,
le résultat représentait le type référencé |
le résultat représente le
type référencé non qualifié cv |
| CWG 1416 | C++98 |
la formulation concernant la qualification cv de niveau supérieur
pouvait être mal interprétée |
formulation améliorée |
| CWG 1431 | C++98 | typeid ne pouvait lever que std::bad_typeid |
peut lever des
classes dérivées correspondantes |
| CWG 1954 | C++98 |
il n'était pas clair si le déréférencement de pointeur nul
pouvait être vérifié dans les sous-expressions de expression |
vérifié uniquement au niveau supérieur |
Voir aussi
|
contient les informations d'un type, la classe retournée par l'opérateur typeid
(classe) |