借鉴某个CPP公众号的文章,拼接代码用于学习。
结论就是推荐使用typeid、FUNCSIG
#include <iostream>
#include <string>
#include <typeinfo>
#include <type_traits>
#ifndef _MSC_VER
#include <cxxabi.h>
#endif // _MSC_VER
namespace TestNs01 {
//编译期打印类型名称
template <typename...> struct type_name {};
template <typename... Ts> struct name_of {
using X = typename type_name<Ts...>::name;
};
template <typename T>
void f(T t) {
//name_of<decltype(t)>();//C++11类型推导decltype
name_of<T>();//C++11类型推导decltype
}
}
namespace TestNs02 {
//借助typeid关键字获得一个std::type_info对象
/*
namespace std {
class type_info {
public:
virtual ~type_info();
bool operator==(const type_info& rhs) const noexcept;
bool before(const type_info& rhs) const noexcept;
size_t hash_code() const noexcept;
const char* name() const noexcept;
type_info(const type_info&) = delete; // cannot be copied
type_info& operator=(const type_info&) = delete; // cannot be copied
};
}
namespace abi {
extern "C" char* __cxa_demangle (const char* mangled_name,
char* buf,
size_t* n,
int* status);
}
*/
template <typename T>
std::string type_name() {
using type = typename std::remove_reference<T>::type;
// 1. 通过typeid获得类型名称
const std::type_info &ti = typeid(type);
const char* name = ti.name();//type_info::name()会丢弃cv及引用修饰符
std::string result;
// 2. 通过gcc/clang扩展API获得Demangled Name
#ifndef _MSC_VER
char* demangled_name = abi::__cxa_demangle(name, nullptr, nullptr, nullptr);
result += demangled_name;
free(demangled_name);
#else
result += name;
#endif // _MSC_VER
// 3. 添加丢弃的修饰
if (std::is_const<type>::value) result += " const";
if (std::is_volatile<type>::value) result += " volatile";
if (std::is_lvalue_reference<T>::value) result += "&";
if (std::is_rvalue_reference<T>::value) result += "&&";
return result;
}
}
namespace TestNs03 {
//用__FUNCSIG__
template <typename T>
/*consteval*/ std::string type_name(){ //C++20引入 consteval 保证函数是在运行时执行的。
std::string_view name, prefix, suffix;
#ifdef __clang__
name = __PRETTY_FUNCTION__;
prefix = "auto type_name() [T = ";
suffix = "]";
#elif defined(__GNUC__)
name = __PRETTY_FUNCTION__;
prefix = "consteval auto type_name() [with T = ";
suffix = "]";
#elif defined(_MSC_VER)
name = __FUNCSIG__;
prefix = "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl TestNs03::type_name<";
suffix = ">(void)";
#endif
name.remove_prefix(prefix.size());
name.remove_suffix(suffix.size());
return std::string(name.data(), name.size());
}
}
namespace TestNs04 {
//Circle C++20静态反射
template <typename... Ts>
void print_types() {
//printf("%d - %s\n", int..., Ts.string)...;//不支持
//printf("unique:\n");
//print_types<Ts.unique...>();//不支持
//printf("sort by type name: \n");
//print_types<Ts.sort(_0.string < _1.string)...>();//不支持
}
//template <typename T>
///*consteval*/ auto type_name() {
// return meta::name_of(reflexpr(T));//不支持
//}
}
struct Base {};
struct Derived : Base {};
int main()
{
//std::cout << "Hello World!\n";
const int i = 0;
const int &il = i;
const int &&ir = std::move(i);//右值引用
const std::string s;
//编译器输出错误信息。不好用。
//TestNs01::name_of<int, float, const char*>();
//TestNs01::name_of<int>();
//TestNs01::f(i);
//借助typeid关键字获得一个std::type_info对象,推荐方式。
std::cout << TestNs02::type_name<decltype(i)>() << "\n"; //int const
std::cout << TestNs02::type_name<decltype(s)>() << "\n"; //class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const
std::cout << TestNs02::type_name<const int&>() << "\n"; //int const&
std::cout << TestNs02::type_name<Base>() << "\n"; //struct Base
std::cout << TestNs02::type_name<Derived>() << "\n"; //struct Derived
//用__FUNCSIG__,部分场景适用。
std::cout << TestNs03::type_name<decltype(i)>() << "\n"; //const int
std::cout << TestNs03::type_name<decltype(s)>() << "\n"; //const class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >
//C++20静态反射,低版本不支持。
//TestNs04::print_types<int, double, const char*, int&&>();//不支持
//constexpr auto __dummy = /*__reflect_print*/(TestNs04::type_name<decltype(i)>());//不支持
}