我想打印一个类型的名称用于调试目的,所以我创建了一个功能来完成这个技巧(事实上,我从另一个SO答案中借用了它,我现在找不到),功能看起来像这样:
template <typename T> std::string TypeName(T)
{
auto name = typeid(T).name();
int status = 0;
std::unique_ptr<char, void(*)(void*)> res {
abi::__cxa_demangle(name, NULL, NULL, &status),
std::free
};
return ((status == 0) ? res.get() : name);
}
工作正常:
int i = 0;
float f = 0.f;
std::cout << TypeName(i) << '\n'; // int
std::cout << TypeName(f) << '\n'; // float, so far so good
std::cout << TypeName(&i) << '\n'; // int *
std::cout << TypeName(&f) << '\n'; // float *, as expected
但它缺乏处理top-level cv-cualifiers和参考的能力:
const int ci = 1;
const float cf = 1.f;
std::cout << TypeName(ci) << '\n'; // int! (instead of const int)
std::cout << TypeName(cf) << '\n'; // float! (instead of const float)
int &ri = i;
float &rf = f;
std::cout << TypeName(ri) << '\n'; // int! (instead of int &)
std::cout << TypeName(rf) << '\n'; // float! (instead of float &)
好吧,我不能说这是意料之外的,因为函数TypeName
是一个函数模板,类型T
遵循模板类型推导,但这个问题使得整个事情几乎无用的。
所以,我的问题是:在创建模板函数(可以获取任何类型作为输入)以获取类型名称而不丢失顶级cv-cualifiers和引用时,是否可以执行任何操作?
提前致谢。
答案 0 :(得分:1)
仅 C ++语言构造可以区分作为 id-expression 的左值和作为引用的左值之间的区别decltype
。以下是如何使用它的示例,包括(ab)使用宏来保持您已有的相同调用模式:
template <typename T> std::string TypeName() {
auto name = typeid(T()).name(); // function type, not a constructor call!
int status = 0;
std::unique_ptr<char, void(*)(void*)> res {
abi::__cxa_demangle(name, NULL, NULL, &status),
std::free
};
std::string ret((status == 0) ? res.get() : name);
if (ret.substr(ret.size() - 3) == " ()") ret.resize(ret.size() - 3);
return ret;
}
#define TypeName(e) TypeName<decltype(e)>()
因为abi::__cxa_demangle
忽略了顶级cv和引用限定符,所以我们构造一个函数类型,然后去掉尾随括号。
这会根据需要提供int const
,int&
,int const&
。