You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在编译期将底层类型转为字符串且不使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 10:50:43