Dada a atenção que esta pergunta / resposta recebe e o feedback valioso do GManNickG , limpei um pouco o código. Duas versões são fornecidas: uma com recursos do C ++ 11 e outra com apenas recursos do C ++ 98.
No arquivo 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
No arquivo type.cpp (requer 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;
}
Ele imprime:
Tipo de ptr_base: Base*
Tipo de ponta:Derived
Testado com g ++ 4.7.2, g ++ 4.9.0 20140302 (experimental), clang ++ 3.4 (tronco 184647), clang 3.5 (tronco 202594) em Linux 64 bits e g ++ 4.7.2 (Mingw32, Win32 XP SP2).
Se você não pode usar os recursos do C ++ 11, veja como isso pode ser feito no C ++ 98, o arquivo type.cpp agora é:
#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
(Atualização de 8 de setembro de 2013)
A resposta aceita (em 7 de setembro de 2013) , quando a chamada para abi::__cxa_demangle()
for bem-sucedida, retorna um ponteiro para um array local, com pilha alocada ... ai!
Observe também que se você fornecer um buffer, abi::__cxa_demangle()
assume que ele está alocado no heap. Alocar o buffer na pilha é um bug (do documento gnu): "Se output_buffer
não for longo o suficiente, ele é expandido usando realloc
." Invocando realloc()
um ponteiro para a pilha ... ai! (Veja também o comentário gentil de Igor Skochinsky .)
Você pode verificar facilmente esses dois bugs: basta reduzir o tamanho do buffer na resposta aceita (em 7 de setembro de 2013) de 1024 para algo menor, por exemplo 16, e dar a ele algo com um nome não superior a 15 (então realloc()
é não chamado). Ainda assim, dependendo do seu sistema e das otimizações do compilador, a saída será: lixo / nada / travamento do programa.
Para verificar o segundo bug: defina o tamanho do buffer para 1 e chame-o com algo cujo nome seja maior que 1 caractere. Quando você o executa, o programa quase com certeza trava ao tentar chamar realloc()
com um ponteiro para a pilha.
(A resposta antiga de 27 de dezembro de 2010)
Mudanças importantes feitas no código de KeithB : o buffer deve ser alocado por malloc ou especificado como NULL. NÃO o coloque na pilha.
É aconselhável verificar esse status também.
Eu não consegui encontrar HAVE_CXA_DEMANGLE
. Eu verifico, __GNUG__
embora isso não garanta que o código seja compilado. Alguém tem uma ideia melhor?
#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>
. Caso contrário, funcionou muito bem, obrigado.output_buffer
Uma região de memória, alocada com malloc, de * bytes de comprimento, na qual o nome demangled é armazenado. Se output_buffer não for longo o suficiente, ele é expandido usando realloc. output_buffer pode ser NULL; nesse caso, o nome demangled é colocado em uma região de memória alocada com malloc.abi::__cxa_demangle
esperava que fosse alocado na pilha. " Muito obrigado por consultar o documento!ret_val
lançado durante a construção. Você pode usar um protetor de escopo para se proteger contra isso.std::unique_ptr<char, decltype(&std::free)>
como assinatura para o ponteiro.O núcleo do Boost contém um demangler. Checkout core / demangle.hpp :
É basicamente um invólucro para
abi::__cxa_demangle
, como foi sugerido anteriormente.fonte
Isso é o que usamos. HAVE_CXA_DEMANGLE é definido apenas se disponível (apenas versões recentes do GCC).
fonte
#include <cxxabi.h>
.Aqui, dê uma olhada em type_strings.hpp, ele contém uma função que faz o que você deseja.
Se você apenas procura por uma ferramenta de demangling, que você pode usar, por exemplo, para desfigurar coisas mostradas em um arquivo de log, dê uma olhada em
c++filt
, que vem com binutils. Ele pode desmantelar nomes de símbolos C ++ e Java.fonte
abi::__cxa_demangle()
e sua laia<cxxabi.h>
não são específicos do GCC - eles podem ter sido apenas GCC no passado distante, mas na época em que este post foi escrito,<cxxabi.h>
era um padrão profundamente ad-hoc. Portanto, embora o link do código da resposta seja DOI, posso garantir que o Clang forneça suporte de primeira classe neste caso ... qv, dalibcxxabi
fonte do Clang : o respectivo decl, impl, enorme teste: git.io/vRTBo , git.io/vRTBh , git.io/vRTRf - os comentários do código de teste observam a implementação do Clang como capaz de mais demangling, de alguma forma, em comparação com o GCC.É a implementação definida, portanto, não é algo que será portátil. No MSVC ++, name () é o nome não decorado, e você deve olhar raw_name () para obter o decorado.
Apenas uma facada no escuro aqui, mas sob gcc, você pode querer dar uma olhada em demangle.h
fonte
Não é uma solução completa, mas você pode querer dar uma olhada no que algumas das macros padrão (ou amplamente suportadas) definem. É comum no código de registro ver o uso das macros:
fonte
Também encontrei uma macro chamada
__PRETTY_FUNCTION__
, que resolve o problema. Fornece um nome de função bonito (figuras :)). Isso é o que eu precisava.Ou seja, me dá o seguinte:
Mas não acho que funcione em outros compiladores.
fonte
Uma ligeira variação da solução de Ali. Se você quiser que o código ainda seja muito semelhante a
typeid(bla).name()
,escrevendo isso ao invés
Typeid(bla).name()
(diferindo apenas na primeira letra maiúscula)então você pode estar interessado nisto:
No arquivo type.hpp
type.cpp permanece o mesmo da solução de Ali
fonte
Dê uma olhada em
__cxa_demangle
que você pode encontrar emcxxabi.h
.fonte
fonte
A solução aceita [1] funciona quase sempre bem. Encontrei pelo menos um caso (e não o chamaria de caso secundário) em que não relata o que eu esperava ... com referências.
Para esses casos, encontrei outra solução, postada na parte inferior.
Caso problemático (usando
type
conforme definido em [1]):produz
Solução (usando
type_name<decltype(obj)>()
, veja o código abaixo):produz
como desejado (pelo menos por mim)
Código . Deve estar em um cabeçalho incluído, não em uma fonte compilada separadamente, devido a problemas de especialização. Consulte a referência indefinida para a função de modelo, por exemplo.
fonte
Sempre quis usar type_info, mas tenho certeza de que o resultado da função de membro name () não é padrão e não retornará necessariamente nada que possa ser convertido em um resultado significativo.
Se você estiver usando apenas um compilador, talvez haja uma função específica do compilador que fará o que você quiser. Verifique a documentação.
fonte
Seguindo a solução de Ali, aqui está a alternativa de modelo C ++ 11 que funcionou melhor para o meu uso.
Uso:
Irá imprimir:
fonte