在 C++ 当中打印类型名称,测试CPP语法

借鉴某个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)>());//不支持
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值