Compte tenu de l'attention que cette question / réponse reçoit et des précieux commentaires de GManNickG , j'ai un peu nettoyé le code. Deux versions sont proposées: une avec des fonctionnalités C ++ 11 et une autre avec uniquement des fonctionnalités C ++ 98.
Dans le fichier type.hpp
#ifndef TYPE_HPP
#define TYPE_HPP
#include <string>
#include <typeinfo>
std::string demangle(const char* name);
template <class T>
std::string type(const T& t) {
return demangle(typeid(t).name());
}
#endif
Dans le fichier type.cpp (nécessite C ++ 11)
#include "type.hpp"
#ifdef __GNUG__
#include <cstdlib>
#include <memory>
#include <cxxabi.h>
std::string demangle(const char* name) {
int status = -4; // some arbitrary value to eliminate the compiler warning
// enable c++11 by passing the flag -std=c++11 to g++
std::unique_ptr<char, void(*)(void*)> res {
abi::__cxa_demangle(name, NULL, NULL, &status),
std::free
};
return (status==0) ? res.get() : name ;
}
#else
// does nothing if not g++
std::string demangle(const char* name) {
return name;
}
#endif
Usage:
#include <iostream>
#include "type.hpp"
struct Base { virtual ~Base() {} };
struct Derived : public Base { };
int main() {
Base* ptr_base = new Derived(); // Please use smart pointers in YOUR code!
std::cout << "Type of ptr_base: " << type(ptr_base) << std::endl;
std::cout << "Type of pointee: " << type(*ptr_base) << std::endl;
delete ptr_base;
}
Il imprime:
Type de ptr_base: Base*
Type de pointee:Derived
Testé avec g ++ 4.7.2, g ++ 4.9.0 20140302 (expérimental), clang ++ 3.4 (trunk 184647), clang 3.5 (trunk 202594) sous Linux 64 bits et g ++ 4.7.2 (Mingw32, Win32 XP SP2).
Si vous ne pouvez pas utiliser les fonctionnalités C ++ 11, voici comment cela peut être fait en C ++ 98, le fichier type.cpp est maintenant:
#include "type.hpp"
#ifdef __GNUG__
#include <cstdlib>
#include <memory>
#include <cxxabi.h>
struct handle {
char* p;
handle(char* ptr) : p(ptr) { }
~handle() { std::free(p); }
};
std::string demangle(const char* name) {
int status = -4; // some arbitrary value to eliminate the compiler warning
handle result( abi::__cxa_demangle(name, NULL, NULL, &status) );
return (status==0) ? result.p : name ;
}
#else
// does nothing if not g++
std::string demangle(const char* name) {
return name;
}
#endif
(Mise à jour du 8 septembre 2013)
La réponse acceptée (au 7 septembre 2013) , lorsque l'appel à abi::__cxa_demangle()
réussit, renvoie un pointeur vers un tableau local alloué par pile ... aïe!
Notez également que si vous fournissez un tampon, abi::__cxa_demangle()
suppose qu'il est alloué sur le tas. Allouer le tampon sur la pile est un bogue (de la doc gnu): "Si ce output_buffer
n'est pas assez long, il est développé avec realloc
." Appel realloc()
d'un pointeur vers la pile ... aïe! (Voir aussi Igor Skochinsky commentaire aimable d' .)
Vous pouvez facilement vérifier ces deux bogues: réduisez simplement la taille de la mémoire tampon dans la réponse acceptée (à partir du 7 septembre 2013) de 1024 à quelque chose de plus petit, par exemple 16, et donnez-lui quelque chose avec un nom ne dépassant pas 15 (ainsi realloc()
est pas appelé). Pourtant, en fonction de votre système et des optimisations du compilateur, la sortie sera: garbage / rien / programme crash.
Pour vérifier le deuxième bogue: définissez la taille de la mémoire tampon sur 1 et appelez-la avec quelque chose dont le nom est plus long que 1 caractère. Lorsque vous l'exécutez, le programme se bloque presque assurément lorsqu'il tente d'appeler realloc()
avec un pointeur vers la pile.
(L'ancienne réponse du 27 décembre 2010)
Modifications importantes apportées au code de KeithB : le tampon doit être soit alloué par malloc, soit spécifié comme NULL.Ne l'allouez PAS sur la pile.
Il est également sage de vérifier ce statut.
Je n'ai pas réussi à trouver HAVE_CXA_DEMANGLE
. Je vérifie __GNUG__
même si cela ne garantit pas que le code sera même compilé. Quelqu'un a une meilleure idée?
#include <cxxabi.h>
const string demangle(const char* name) {
int status = -4;
char* res = abi::__cxa_demangle(name, NULL, NULL, &status);
const char* const demangled_name = (status==0)?res:name;
string ret_val(demangled_name);
free(res);
return ret_val;
}
#include <cxxabi.h>
. Sinon, a très bien fonctionné, merci.output_buffer
Une région de mémoire, allouée avec malloc, de * length octets, dans laquelle le nom démêlé est stocké. Si output_buffer n'est pas assez long, il est développé à l'aide de realloc. output_buffer peut à la place être NULL; dans ce cas, le nom démêlé est placé dans une région de mémoire allouée avec malloc.abi::__cxa_demangle
m'attendais à ce qu'il soit alloué sur le tas. " Merci beaucoup d'avoir recherché le document!ret_val
projection pendant la construction. Vous pouvez utiliser une lunette de protection pour vous en prémunir.std::unique_ptr<char, decltype(&std::free)>
comme signature pour votre pointeur.Le noyau Boost contient un démêleur. Commander core / demangle.hpp :
C'est fondamentalement juste un wrapper pour
abi::__cxa_demangle
, comme cela a été suggéré précédemment.la source
C'est ce que nous utilisons. HAVE_CXA_DEMANGLE n'est défini que s'il est disponible (versions récentes de GCC uniquement).
la source
#include <cxxabi.h>
.Ici, jetez un œil à type_strings.hpp, il contient une fonction qui fait ce que vous voulez.
Si vous cherchez simplement un outil de démêlage, que vous pourriez utiliser par exemple pour modifier les éléments affichés dans un fichier journal, jetez un œil à
c++filt
, qui est fourni avec binutils. Il peut démêler les noms de symboles C ++ et Java.la source
abi::__cxa_demangle()
et ses semblables ne<cxxabi.h>
sont pas spécifiques à GCC - ils peuvent avoir été GCC seulement dans un passé lointain, mais au moment de la rédaction de cet article, il<cxxabi.h>
s'agissait d'une norme ad hoc enracinée. Donc, alors que le lien de code de la réponse était DOI, je peux garantir que Clang fournisse un support de première classe dans ce cas ... qv, de lalibcxxabi
source de Clang : le test respectivement decl, impl, énorme test: git.io/vRTBo , git.io/vRTBh , git.io/vRTRf - les commentaires du code de test indiquent que l'implémentation Clang est capable de plus de démêlage, d'une manière ou d'une autre, par rapport à GCC.C'est une implémentation définie, donc ce n'est pas quelque chose qui va être portable. Dans MSVC ++, name () est le nom non décoré, et vous devez regarder raw_name () pour obtenir celui décoré.
Juste un coup de couteau dans le noir ici, mais sous gcc, vous voudrez peut-être regarder demangle.h
la source
Ce n'est pas une solution complète, mais vous voudrez peut-être regarder ce que définissent certaines des macros standard (ou largement prises en charge). Il est courant dans le code de journalisation de voir l'utilisation des macros:
la source
J'ai aussi trouvé une macro appelée
__PRETTY_FUNCTION__
, qui fait l'affaire. Cela donne un joli nom de fonction (chiffres :)). C'est ce dont j'avais besoin.Ie cela me donne ce qui suit:
Mais je ne pense pas que cela fonctionne sur d'autres compilateurs.
la source
Une légère variation sur la solution d'Ali. Si vous voulez que le code soit toujours très similaire à
typeid(bla).name()
,écrire ceci à la place
Typeid(bla).name()
(ne différant que par la première lettre majuscule)alors vous pourriez être intéressé par ceci:
Dans le fichier type.hpp
type.cpp reste le même que dans la solution d'Ali
la source
Jetez un œil à
__cxa_demangle
ce que vous pouvez trouver surcxxabi.h
.la source
la source
La solution acceptée [1] fonctionne généralement bien. J'ai trouvé au moins un cas (et je ne l'appellerais pas un cas d'angle) où il ne rapporte pas ce que j'attendais ... avec des références.
Pour ces cas, j'ai trouvé une autre solution, affichée en bas.
Cas problématique (en utilisant
type
comme défini dans [1]):produit
Solution (en utilisant
type_name<decltype(obj)>()
, voir le code ci-dessous):produit
comme désiré (au moins par moi)
Code . Il doit être dans un en-tête inclus, pas dans une source compilée séparément, en raison de problèmes de spécialisation. Voir la référence non définie à la fonction de modèle par exemple.
la source
J'ai toujours voulu utiliser type_info, mais je suis sûr que le résultat de la fonction membre name () n'est pas standard et ne retournera pas nécessairement tout ce qui peut être converti en un résultat significatif.
Si vous vous en tenez à un compilateur, il peut y avoir une fonction spécifique au compilateur qui fera ce que vous voulez. Consultez la documentation.
la source
Suite à la solution d'Ali, voici l' alternative basée sur le modèle C ++ 11 qui fonctionnait le mieux pour mon utilisation.
Usage:
Imprimera:
la source