Compte tenu de l'attention portée à cette question / réponse reçoit, et les précieux commentaires de GManNickG, j'ai nettoyé un peu le code. Deux versions: l'une avec C++11 caractéristiques et l'autre avec seulement C++98 caractéristiques.
Dans le fichier de type.php
#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 le 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
Utilisation:
#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 (tronc 184647), clang 3.5 (tronc 202594) sur Linux 64 bits et g++ 4.7.2 (Mingw32, Win32 XP SP2).
Si vous ne pouvez pas utiliser le C++11 caractéristiques, voici comment on peut le faire 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 à partir du 8 septembre, 2013)
La accepté de répondre (comme de Sep 7, 2013), lors de l'appel à abi::__cxa_demangle()
est un succès, retourne un pointeur vers un local, pile allouée tableau... aïe!
Notez également que si vous fournissez un tampon, abi::__cxa_demangle()
suppose qu'il est alloué sur le tas. L'allocation de la mémoire tampon dans la pile est un bug (à partir de la gnu doc): "Si output_buffer
n'est pas assez long, elle est étendue à l'aide d' realloc
." Appelant realloc()
sur un pointeur sur la pile... aïe! (Voir aussi Igor Skochinsky'genre de commentaire.)
Vous pouvez facilement vérifier ces deux bugs: il suffit de réduire la taille de la mémoire tampon dans l'acceptation de la réponse (comme d'Sep 7, 2013) de 1024 à quelque chose de plus petit, par exemple 16, et de lui donner quelque chose avec un nom pas plus que 15 (si realloc()
est pas appelé). Toujours, selon votre système et les optimisations du compilateur, la sortie sera: déchets / rien / plantage du programme.
Pour vérifier la deuxième bug: définir la taille de la mémoire tampon de 1 et de l'appeler avec quelque chose dont le nom est plus long que 1 caractère. Lorsque vous l'exécutez, le programme presque assurément se bloque, comme il tente d'appeler realloc()
avec un pointeur sur la pile.
(La vieille réponse du 27 Décembre 2010)
Modifications importantes apportées à KeithB du code: le tampon doit être allouée par malloc ou NULL. Ne PAS allouer sur la pile.
Il est sage de vérifier le statut.
Je n'ai pas réussi à trouver de l' HAVE_CXA_DEMANGLE
. Je vérifie __GNUG__
bien que cela ne garantit pas que le code même de la compilation. 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;
}