如何在编译期将底层类型转为字符串且不使用RTTI?
编译期获取枚举底层类型的字符串表示(无需手动声明/RTTI)
可以实现这个需求——不需要为每个类型手动声明静态结构,也不依赖RTTI,完全借助C++编译期模板特性和编译器内置的类型名称标识来完成,效果类似针对类型的编译期字符串化。
核心实现思路
利用编译器内置的__PRETTY_FUNCTION__(GCC/Clang)或__FUNCSIG__(MSVC)宏,这些宏在模板函数中会包含具体的模板参数类型信息。通过编译期字符串截取,提取出目标类型的名称字符串,再结合constexpr哈希函数完成断言验证。
完整代码示例
#include <string_view> #include <type_traits> // constexpr版FNV1A哈希函数 constexpr std::size_t MakeHashFNV1A(const char* str, std::size_t hash = 14695981039346656037ULL) { return *str ? MakeHashFNV1A(str + 1, (hash ^ static_cast<std::size_t>(*str)) * 1099511628211ULL) : hash; } // 通用类型名称提取模板 template<typename T> struct TypeName { private: static constexpr const char* get_func_str() { #ifdef __GNUC__ || __clang__ return __PRETTY_FUNCTION__; #elif _MSC_VER return __FUNCSIG__; #endif } // 编译期截取类型名称(适配不同编译器的格式) static constexpr std::string_view extract_type_name() { constexpr auto func_str = get_func_str(); constexpr std::string_view sv(func_str); #ifdef __GNUC__ || __clang__ // GCC/Clang格式:static constexpr const char* TypeName<T>::get_func_str() [with T = int] constexpr auto start_pos = sv.find("T = ") + 4; constexpr auto end_pos = sv.find("]", start_pos); #elif _MSC_VER // MSVC格式:const char *__cdecl TypeName<int>::get_func_str(void) constexpr auto start_pos = sv.find("TypeName<") + 9; constexpr auto end_pos = sv.find(">", start_pos); #endif return sv.substr(start_pos, end_pos - start_pos); } public: static constexpr std::string_view value = extract_type_name(); }; // 适配枚举底层类型的传递(直接复用已有类型的名称提取) template<typename Enum> struct TypeName<std::underlying_type_t<Enum>> : TypeName<typename std::underlying_type<Enum>::type> {}; // 定义需求中的MAGIC_STRINGIFY宏 #define MAGIC_STRINGIFY(T) TypeName<T>::value.data() // 测试用例 enum ESomeEnum : int {}; enum class EAnotherEnum : unsigned long long {}; static_assert(MakeHashFNV1A(MAGIC_STRINGIFY(std::underlying_type_t<ESomeEnum>)) == MakeHashFNV1A("int")); static_assert(MakeHashFNV1A(MAGIC_STRINGIFY(std::underlying_type_t<EAnotherEnum>)) == MakeHashFNV1A("unsigned long long"));
关键说明
- 无手动声明:模板会自动推导任意类型(包括枚举底层类型)的名称,无需为每个类型单独编写结构。
- 无RTTI依赖:整个过程完全在编译期通过模板和constexpr操作完成,禁用RTTI(如编译时加
-fno-rtti)也不影响功能。 - 编译器兼容性:需要根据使用的编译器调整字符串截取逻辑,上述代码已适配GCC/Clang和MSVC。
- 编译期安全:所有操作都在编译期完成,静态断言会在编译阶段验证哈希值是否匹配,不会产生运行时开销。
内容的提问来源于stack exchange,提问作者not-a-real
相关产品推荐
相关产品推荐

