C++ 取消混合std::type_info::name的结果
我目前正在编写一些日志代码,其中包括打印有关调用函数的信息。这应该比较容易,标准C++有一个<代码> Type信息> /Cuff>类。它包含typeid的类/函数/等的名称,但已损坏。这不是很有用。例如,C++ 取消混合std::type_info::name的结果,c++,gcc,name-mangling,clang,msvc,c++17,C++,Gcc,Name Mangling,Clang,Msvc,C++17,我目前正在编写一些日志代码,其中包括打印有关调用函数的信息。这应该比较容易,标准C++有一个 Type信息> /Cuff>类。它包含typeid的类/函数/等的名称,但已损坏。这不是很有用。例如,typeid(std::vector).name()返回st6vectorisaiee 有没有办法从中产生有用的东西?对于上述示例,类似于std::vector。如果它只适用于非模板类,那也可以 这个解决方案应该适用于gcc,但是如果我可以移植它,那就更好了。它是用来记录日志的,所以它不是很重要,不能关
typeid(std::vector).name()
返回st6vectorisaiee
有没有办法从中产生有用的东西?对于上述示例,类似于std::vector
。如果它只适用于非模板类,那也可以
这个解决方案应该适用于gcc,但是如果我可以移植它,那就更好了。它是用来记录日志的,所以它不是很重要,不能关闭,但它应该有助于调试。它是由实现定义的,所以它不是可移植的。在MSVC++中,name()是未修饰的名称,您必须查看原始名称()才能得到修饰的名称。
这里只是一个暗箱操作,但在gcc下,您可能想看看我一直想使用type_info,但我确信name()成员函数的结果是非标准的,不一定会返回任何可以转换为有意义的结果。
如果您坚持使用一个编译器,那么可能有一个特定于编译器的函数可以实现您想要的功能。查看文档。查看
\uuucxa\u demangle
,您可以在cxxabi.h
中找到这是我们使用的。HAVE_CXA_DEMANGLE仅在可用时设置(仅限GCC的最新版本)
这不是一个完整的解决方案,但您可能希望了解一些标准(或广泛支持的)宏的定义。在日志代码中,查看宏的使用是很常见的:
__FUNCTION__
__FILE__
__LINE__
e.g.:
log(__FILE__, __LINE__, __FUNCTION__, mymessage);
在这里,看一看它包含一个函数,它可以实现您想要的功能
如果您只是寻找一个Demanling工具,例如,您可以使用它来处理日志文件中显示的内容,那么请查看binutils附带的
c++filt
。它可以分解C++和java符号名。 我也发现了一个宏叫做“代码>”它给出了一个漂亮的函数名(图:)。这就是我需要的
也就是说,它给了我以下信息:
virtual bool mutex::do_unlock()
但我认为它在其他编译器上不起作用。//KeithB的解决方案很好,但有一个严重的缺陷,除非buf是静态的
// KeithB's solution is good, but has one serious flaw in that unless buf is static
// it'll get trashed from the stack before it is returned in res - and will point who-knows-where
// Here's that problem fixed, but the code is still non-re-entrant and not thread-safe.
// Anyone care to improve it?
#include <cxxabi.h>
// todo: javadoc this properly
const char* demangle(const char* name)
{
static char buf[1024];
size_t size = sizeof(buf);
int status;
// todo:
char* res = abi::__cxa_demangle (name,
buf,
&size,
&status);
buf[sizeof(buf) - 1] = 0; // I'd hope __cxa_demangle does this when the name is huge, but just in case.
return res;
}
//在以res返回之前,它将从堆栈中被丢弃,并且将指向谁知道在哪里
//这个问题已经解决了,但是代码仍然是不可重入的,并且不是线程安全的。
//有人想改进吗?
#包括
//todo:javadoc正确地描述了这一点
常量字符*demangle(常量字符*名称)
{
静态字符buf[1024];
尺寸=尺寸(buf);
智力状态;
//待办事项:
char*res=abi::\uuucxa\udemangle(名称,
缓冲器,
&大小,
&地位);
buf[sizeof(buf)-1]=0;//我希望uu cxa\u demangle在名称庞大时会这样做,但以防万一。
返回res;
}
考虑到这个问题/答案受到的关注和来自的宝贵反馈,我已经稍微整理了一下代码。给出了两个版本:一个具有C++11特性,另一个仅具有C++98特性
在文件中键入.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());
}
*/
class Typeid {
public:
template <class T>
Typeid(const T& t) : typ(typeid(t)) {}
std::string name() { return demangle(typ.name()); }
private:
const std::type_info& typ;
};
#endif
\ifndef型水电站
#定义HPP类型
#包括
#包括
std::string demangle(const char*name);
模板
标准::字符串类型(常量T&T){
返回demangle(typeid(t).name());
}
#恩迪夫
在文件中键入.cpp(需要C++11)
#包括“type.hpp”
#ifdef_u_GNUG__
#包括
#包括
#包括
std::string demangle(常量字符*名称){
int status=-4;//消除编译器警告的任意值
//通过将标志-std=c++11传递给g来启用c++11++
标准::唯一的\u ptr res{
abi::_cxa_demangle(名称、空值、空值和状态),
免费
};
return(status==0)?res.get():name;
}
#否则
//如果没有g什么都不做++
std::string demangle(常量字符*名称){
返回名称;
}
#恩迪夫
用法:
#包括
#包括“类型.hpp”
结构Base{virtual~Base(){};
派生结构:公共基{};
int main(){
Base*ptr_Base=new-Derived();//请在代码中使用智能指针!
std::cout对Ali的解决方案有一点不同。如果您希望代码仍然与
typeid(bla.name()
改写这个
Typeid(bla.name()
(只在大写首字母上有所不同)
那么您可能会对此感兴趣:
在文件中键入.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());
}
*/
class Typeid {
public:
template <class T>
Typeid(const T& t) : typ(typeid(t)) {}
std::string name() { return demangle(typ.name()); }
private:
const std::type_info& typ;
};
#endif
\ifndef型水电站
#定义HPP类型
#包括
#包括
std::string demangle(const char*name);
/*
模板
标准::字符串类型(常量T&T){
返回demangle(typeid(t).name());
}
*/
类类型ID{
公众:
模板
Typeid(const T&T):类型(Typeid(T)){}
std::string name(){return-demangle(typ.name());}
私人:
常数标准::类型信息和类型;
};
#恩迪夫
类型。cpp与阿里的解决方案保持一致Boost core包含demangler。签出:
#包括
#包括
#包括
模板结构X
{
};
int main()
{
char const*name=typeid(X).name();
std::cout这个[1]工作得很好。
我发现至少有一个案例(我不会称之为角落案例)没有报告我所期望的情况…有参考资料
对于这些情况,我找到了另一个解决方案,张贴在底部
问题案例(使用[1]中定义的类型
):
解决方案(使用键入\u name()
,请参见下面的代码):
如所愿(至少由我)
代码
.
由于专门化问题,它必须位于包含的头文件中,而不是单独编译的源文件中
#ifndef _MSC_VER
# include <cxxabi.h>
#endif
#include <memory>
#include <string>
#include <cstdlib>
template <class T>
std::string
type_name()
{
typedef typename std::remove_reference<T>::type TR;
std::unique_ptr<char, void(*)(void*)> own
(
#ifndef _MSC_VER
abi::__cxa_demangle(typeid(TR).name(), nullptr,
nullptr, nullptr),
#else
nullptr,
#endif
std::free
);
std::string r = own != nullptr ? own.get() : typeid(TR).name();
if (std::is_const<TR>::value)
r += " const";
if (std::is_volatile<TR>::value)
r += " volatile";
if (std::is_lvalue_reference<T>::value)
r += "&";
else if (std::is_rvalue_reference<T>::value)
r += "&&";
return r;
}
\ifndef\u MSC\u VER
#包括
#恩迪夫
#包括
#包括
#包括
模板
int i = 1;
cout << "Type of " << "i" << " is " << type(i) << endl;
int & ri = i;
cout << "Type of " << "ri" << " is " << type(ri) << endl;
Type of i is int
Type of ri is int
cout << "Type of " << "i" << " is " << type_name<decltype(i)>() << endl;
cout << "Type of " << "ri" << " is " << type_name<decltype(ri)>() << endl;
Type of i is int
Type of ri is int&
#ifndef _MSC_VER
# include <cxxabi.h>
#endif
#include <memory>
#include <string>
#include <cstdlib>
template <class T>
std::string
type_name()
{
typedef typename std::remove_reference<T>::type TR;
std::unique_ptr<char, void(*)(void*)> own
(
#ifndef _MSC_VER
abi::__cxa_demangle(typeid(TR).name(), nullptr,
nullptr, nullptr),
#else
nullptr,
#endif
std::free
);
std::string r = own != nullptr ? own.get() : typeid(TR).name();
if (std::is_const<TR>::value)
r += " const";
if (std::is_volatile<TR>::value)
r += " volatile";
if (std::is_lvalue_reference<T>::value)
r += "&";
else if (std::is_rvalue_reference<T>::value)
r += "&&";
return r;
}
std::__cxx11::basic_string<char>
std::basic_string<char>