Dada la atención que recibe esta pregunta / respuesta y los valiosos comentarios de GManNickG , he limpiado un poco el código. Se dan dos versiones: una con características de C ++ 11 y otra con solo características de C ++ 98.
En archivo 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
En el archivo type.cpp (requiere 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
Uso:
#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;
}
Imprime:
Tipo de ptr_base: Base*
Tipo de puntero:Derived
Probado con g ++ 4.7.2, g ++ 4.9.0 20140302 (experimental), clang ++ 3.4 (troncal 184647), clang 3.5 (troncal 202594) en Linux de 64 bits y g ++ 4.7.2 (Mingw32, Win32 XP SP2).
Si no puede usar las funciones de C ++ 11, así es como se puede hacer en C ++ 98, el archivo type.cpp es ahora:
#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
(Actualización del 8 de septiembre de 2013)
La respuesta aceptada (a partir del 7 de septiembre de 2013) , cuando la llamada a abi::__cxa_demangle()
es exitosa, devuelve un puntero a una matriz local asignada a la pila ... ¡ay!
También tenga en cuenta que si proporciona un búfer, se abi::__cxa_demangle()
supone que está asignado en el montón. Asignar el búfer en la pila es un error (del gnu doc): "Si output_buffer
no es lo suficientemente largo, se expande usando realloc
". Invocando realloc()
un puntero a la pila ... ¡ay! (Véase también el amable comentario de Igor Skochinsky ).
Puede verificar fácilmente estos dos errores: simplemente reduzca el tamaño del búfer en la respuesta aceptada (a partir del 7 de septiembre de 2013) de 1024 a algo más pequeño, por ejemplo 16, y asígnele algo con un nombre que no sea más largo que 15 (también lo realloc()
es no llamado). Aún así, dependiendo de su sistema y las optimizaciones del compilador, el resultado será: basura / nada / bloqueo del programa.
Para verificar el segundo error: establezca el tamaño del búfer en 1 y llámelo con algo cuyo nombre tenga más de 1 carácter. Cuando lo ejecuta, es casi seguro que el programa se bloquee cuando intenta llamar realloc()
con un puntero a la pila.
(La respuesta anterior del 27 de diciembre de 2010)
Cambios importantes realizados en el código de KeithB : el búfer debe ser asignado por malloc o especificado como NULL. NO lo asigne a la pila.
También es aconsejable comprobar ese estado.
No pude encontrar HAVE_CXA_DEMANGLE
. Verifico, __GNUG__
aunque eso no garantiza que el código incluso se compile. ¿Alguien tiene una idea mejor?
#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>
. De lo contrario funcionó muy bien, gracias.output_buffer
una región de memoria, asignada con malloc, de * bytes de longitud, en la que se almacena el nombre demandado. Si output_buffer no es lo suficientemente largo, se expande usando realloc. output_buffer en su lugar puede ser NULL; en ese caso, el nombre demandado se coloca en una región de memoria asignada con malloc.abi::__cxa_demangle
esperaba que se asignara en el montón " . ¡Muchas gracias por buscar el documento!ret_val
lanza durante la construcción. Puede usar un protector de alcance para protegerse contra eso.std::unique_ptr<char, decltype(&std::free)>
como firma para su puntero.Boost core contiene un demangler. Checkout core / demangle.hpp :
Básicamente es solo un contenedor para
abi::__cxa_demangle
, como se sugirió anteriormente.fuente
Esto es lo que usamos. HAVE_CXA_DEMANGLE solo se establece si está disponible (solo versiones recientes de GCC).
fuente
#include <cxxabi.h>
.Aquí, eche un vistazo a type_strings.hpp , contiene una función que hace lo que quiere.
Si solo busca una herramienta de demanda, que, por ejemplo, podría usar para modificar las cosas que se muestran en un archivo de registro, eche un vistazo
c++filt
, que viene con binutils. Puede exigir nombres de símbolos de C ++ y Java.fuente
abi::__cxa_demangle()
y los de su tipo<cxxabi.h>
no son específicos de GCC ; es posible que hayan sido solo de GCC en el pasado distante, pero en el momento de redactar este artículo,<cxxabi.h>
era un estándar ad-hoc arraigado. Entonces, si bien el enlace del código de la respuesta era DOI, puedo garantizar que Clang proporcione soporte de primera clase en este caso ... qv, de lalibcxxabi
fuente de Clang : el respectivo decl, impl, enorme prueba: git.io/vRTBo , git.io/vRTBh , git.io/vRTRf : los comentarios del código de prueba señalan que la implementación de Clang es capaz de exigir más , de alguna manera, que GCC.Está definida por la implementación, por lo que no es algo que sea portátil. En MSVC ++, name () es el nombre sin decorar, y tienes que mirar raw_name () para obtener el decorado.
Solo una puñalada en la oscuridad aquí, pero debajo de gcc, es posible que desee ver demangle.h
fuente
No es una solución completa, pero es posible que desee ver lo que definen algunas de las macros estándar (o ampliamente admitidas). Es común en el código de registro ver el uso de las macros:
fuente
También encontré una macro llamada
__PRETTY_FUNCTION__
, que hace el truco. Da un bonito nombre de función (cifras :)). Esto es lo que necesitaba.Es decir, me da lo siguiente:
Pero no creo que funcione en otros compiladores.
fuente
Una ligera variación de la solución de Ali. Si desea que el código siga siendo muy similar a
typeid(bla).name()
,escribiendo esto en su lugar
Typeid(bla).name()
(difiere solo en la primera letra mayúscula)entonces te puede interesar esto:
En archivo type.hpp
type.cpp permanece igual que en la solución de Ali
fuente
Eche un vistazo a
__cxa_demangle
lo que puede encontrar encxxabi.h
.fuente
fuente
La solución aceptada [1] funciona principalmente bien. Encontré al menos un caso (y no lo llamaría un caso de esquina) donde no informa lo que esperaba ... con referencias.
Para esos casos, encontré otra solución, publicada en la parte inferior.
Caso problemático (utilizando
type
como se define en [1]):produce
Solución (usando
type_name<decltype(obj)>()
, vea el código a continuación):produce
como desee (al menos por mí)
Codigo . Tiene que estar en un encabezado incluido, no en una fuente compilada por separado, debido a problemas de especialización. Consulte la referencia no definida a la función de plantilla, por ejemplo.
fuente
Siempre quise usar type_info, pero estoy seguro de que el resultado de la función miembro name () no es estándar y no necesariamente devolverá nada que pueda convertirse en un resultado significativo.
Si se apega a un compilador, tal vez haya una función específica del compilador que hará lo que desee. Consulta la documentación.
fuente
Siguiendo la solución de Ali, aquí está la alternativa con plantilla de C ++ 11 que funcionó mejor para mi uso.
Uso:
Imprimirá:
fuente