'typeid' contre 'typeof' en C ++

159

Je me demande quelle est la différence entre typeidet typeofen C ++. Voici ce que je sais:

  • typeidest mentionné dans la documentation de type_info qui est définie dans le fichier d'en-tête C ++ typeinfo .

  • typeofest défini dans l'extension GCC pour C et dans la bibliothèque C ++ Boost .

Aussi, voici le test de code de test que j'ai créé où j'ai découvert et qui typeidne renvoie pas ce que j'attendais. Pourquoi?

main.cpp

#include <iostream>  
#include <typeinfo>  //for 'typeid' to work  

class Person {  
    public:
    // ... Person members ...  
    virtual ~Person() {}  
};  

class Employee : public Person {  
    // ... Employee members ...  
};  

int main () {  
    Person person;  
    Employee employee;  
    Person *ptr = &employee;  
    int t = 3;  

    std::cout << typeid(t).name() << std::endl;  
    std::cout << typeid(person).name() << std::endl;   // Person (statically known at compile-time)  
    std::cout << typeid(employee).name() << std::endl; // Employee (statically known at compile-time)  
    std::cout << typeid(ptr).name() << std::endl;      // Person * (statically known at compile-time)  
    std::cout << typeid(*ptr).name() << std::endl;     // Employee (looked up dynamically at run-time  
                                                       // because it is the dereference of a pointer
                                                       // to a polymorphic class)  
 }  

production:

bash-3.2$ g++ -Wall main.cpp -o main  
bash-3.2$ ./main   
i  
6Person  
8Employee  
P6Person  
8Employee
Tim
la source
8
De quelle manière pensez-vous que votre code n'imprime pas les bons noms de type? Cela me va bien. La chaîne réelle renvoyée par name()est définie par l' implémentation. Il n'est pas nécessaire qu'il s'agisse d'un nom d'identifiant C ++ valide, mais simplement de quelque chose qui identifie de manière unique le type. Il semble que votre implémentation utilise le schéma général de modification des noms du compilateur.
Rob Kennedy
Merci Rob! Je m'attendais à ce que les noms de types soient exactement les mêmes que ceux que j'ai vus dans en.wikipedia.org/wiki/Typeid. Que peut faire ici le dénigrement?
Tim
Si vous êtes nouveau dans typeid comme moi: vous avez besoin d'une fonction virtuelle dans le type de base pour activer la vtable ou la dernière ligne imprimera le type de base.
jw_

Réponses:

200

Le langage C ++ n'a rien de tel que typeof. Vous devez rechercher une extension spécifique au compilateur. Si vous parlez de GCC typeof, une fonctionnalité similaire est présente dans C ++ 11 via le mot-clé decltype. Encore une fois, C ++ n'a pas de tel typeofmot clé.

typeidest un opérateur de langage C ++ qui renvoie des informations d'identification de type au moment de l'exécution. Il renvoie essentiellement un type_infoobjet, qui est comparable à l'égalité avec d'autres type_infoobjets.

Notez que la seule propriété définie de l' type_infoobjet renvoyé est d'être comparable à l'égalité et à la non-égalité, c'est-à-dire que les type_infoobjets décrivant différents types doivent être comparés non égaux, tandis que les type_infoobjets décrivant le même type doivent comparer égaux. Tout le reste est défini par l'implémentation. Les méthodes qui renvoient divers "noms" ne sont pas garanties de renvoyer quoi que ce soit de lisible par l'homme, et même pas garanties de renvoyer quoi que ce soit.

Notez également que ce qui précède implique probablement (bien que la norme ne semble pas le mentionner explicitement) que des applications consécutives typeiddu même type peuvent renvoyer des type_infoobjets différents (qui, bien sûr, doivent encore comparer égaux).

Fourmi
la source
1
cela n'aurait-il pas besoin d'une mise à jour depuis C ++ 11 decltype? Je ne sais pas quelle est la politique générale, mais comme la question est étiquetée, C++je m'attendrais à ce qu'elle fasse référence à la dernière norme. Repenser la question comme C++03serait également une option à mon humble avis. Personnellement, je suis parfois assez confus, car je dois utiliser preC ++ 11 au travail et parfois je ne suis pas sûr de ce qui est vrai "pre11" ou "post11".
idclev 463035818
11
FYI, decltypen'est pas un remplacement pour typeof. typeoffonctionne aussi sur les types tandis decltypeque non. Par exemple, typeof(int)is intwhile decltype(int)est une erreur.
Shahbaz
1
"les type_infoobjets décrivant différents types doivent être comparés non égaux" . En fait, ce n'est pas garanti . L'opérateur d'inégalité a été supprimé dans C ++ 20 pour (je suppose) décourager de s'appuyer sur différents types de comparaison non-égaux. Mais si vous y réfléchissez, l'égalité n'est pas sûre si l'inégalité n'est pas sûre.
Indiana Kernick le
51

La principale différence entre les deux est la suivante

  • typeof est une construction au moment de la compilation et renvoie le type tel que défini au moment de la compilation
  • typeid est une construction d'exécution et donne donc des informations sur le type d'exécution de la valeur.

typeof Référence: http://www.delorie.com/gnu/docs/gcc/gcc_36.html

Référence typeid: https://en.wikipedia.org/wiki/Typeid

JaredPar
la source
Merci JaredPar! J'ai quelques nouvelles questions dans le post mis à jour après avoir lu vos réponses. Par exemple, s'il est également vrai que leurs retours sont utilisés à des fins différentes: le retour de typeof est utilisé comme mot clé de type qui peut définir une variable, mais le retour de typeid ne le peut pas?
Tim
26

typeidpeut fonctionner à l'exécution et retourner un objet décrivant le type d'exécution de l'objet, qui doit être un pointeur vers un objet d'une classe avec des méthodes virtuelles pour que RTTI (informations de type à l'exécution) soit stocké dans la classe. Il peut également donner le type à la compilation d'une expression ou d'un nom de type, s'il n'est pas donné un pointeur vers une classe avec des informations de type à l'exécution.

typeofest une extension GNU, et vous donne le type de n'importe quelle expression au moment de la compilation. Cela peut être utile, par exemple, pour déclarer des variables temporaires dans des macros qui peuvent être utilisées sur plusieurs types. En C ++, vous utiliseriez généralement des modèles à la place.

Brian Campbell
la source
5
Autant que je sache, typeidacceptera n'importe quelle expression, pas seulement celles qui évaluent à des objets avec des méthodes virtuelles. De plus, typeidacceptera un nom de type , pas seulement une expression. Vous pouvez dire typeid(5)ou typeid(std::string)si vous voulez.
Rob Kennedy
1
J'ai clarifié ma réponse pour que cela soit clair; typeid peut renvoyer des informations de type à l'exécution si disponibles, mais fournira des informations de type à la compilation pour tout le reste.
Brian Campbell
Merci, Brian et Rob! J'ai quelques nouvelles questions dans le post mis à jour après avoir lu vos réponses.
Tim
22

Répondre à la question supplémentaire:

mon code de test suivant pour typeid ne produit pas le nom de type correct. Qu'est-ce qui ne va pas?

Il n'y a rien de mal. Ce que vous voyez est la représentation sous forme de chaîne du nom du type. Le C ++ standard ne force pas les compilateurs à émettre le nom exact de la classe, c'est juste à l'implémenteur (fournisseur du compilateur) de décider ce qui convient. En bref, les noms appartiennent au compilateur.


Ce sont deux outils différents. typeofrenvoie le type d'une expression, mais ce n'est pas standard. Dans C ++ 0x il y a quelque chose decltypequi s'appelle qui fait le même travail AFAIK.

decltype(0xdeedbeef) number = 0; // number is of type int!
decltype(someArray[0]) element = someArray[0];

Alors qu'il typeidest utilisé avec les types polymorphes. Par exemple, disons que catdérive animal:

animal* a = new cat; // animal has to have at least one virtual function
...
if( typeid(*a) == typeid(cat) )
{
    // the object is of type cat! but the pointer is base pointer.
}
AraK
la source
Merci, Arak! Je viens de mettre à jour le message avec de nouvelles questions. Jetez-y un œil si possible.
Tim
4

typeid fournit le type des données au moment de l'exécution, lorsqu'il est demandé. Typedef est une construction au moment de la compilation qui définit un nouveau type comme indiqué par la suite. Il n'y a pas de typeof dans la sortie C ++ qui apparaît comme (affiché comme des commentaires inscrits):

std::cout << typeid(t).name() << std::endl;  // i
std::cout << typeid(person).name() << std::endl;   // 6Person
std::cout << typeid(employee).name() << std::endl; // 8Employee
std::cout << typeid(ptr).name() << std::endl;      // P6Person
std::cout << typeid(*ptr).name() << std::endl;     //8Employee
Dr Debasish Jana
la source
3

Vous pouvez utiliser Boost demangle pour créer un joli nom:

#include <boost/units/detail/utility.hpp>

et quelque chose comme

To_main_msg_evt ev("Failed to initialize cards in " + boost::units::detail::demangle(typeid(*_IO_card.get()).name()) + ".\n", true, this);
Patrick K
la source