编译期类型名转字符串需用 constexpr 模板特化配合 static constexpr 字符数组实现,因 std::type_info::name() 是运行时且实现定义的;主模板触发编译错误防漏特化,特化必须含 '\0';宏或 PRETTY_FUNCTION 等方案不可靠且非字面量;C++20 无自动通用解法,需手动特化或构建期代码生成。

编译期类型名转字符串,std::type_info::name() 不行
运行时返回的 std::type_info::name() 结果是实现定义的(比如 GCC 返回 "i" 表示 int,Clang 可能是 "i" 或更长的 mangled 名),不可靠,也不满足“编译期”要求。真正需要的是在模板实例化时就确定、可被 constexpr 消费的字面量字符串。
用 constexpr 模板特化 + static constexpr 字符数组
最直接可控的方式:为每个目标类型显式特化一个模板,返回固定长度的字符数组。注意必须用数组而非 const char*,否则无法用于 constexpr 上下文(指针值非字面量)。
- 定义主模板触发编译错误,避免漏特化:
template<typename T> struct type_name { static constexpr const char value[] = "unknown"; }; - 为常用类型特化(注意结尾
'\0'必须包含):template<> struct type_name<int> { static constexpr const char value[] = "int"; }; template<> struct type_name<std::string> { static constexpr const char value[] = "std::string"; }; - 使用时直接取
type_name<T>::value,它是constexpr,可作数组大小、static_assert条件等
自动推导类型名?C++20 __VA_OPT__ 和宏有局限
有人尝试用宏拼接 __PRETTY_FUNCTION__ 或 __func__ 提取类型名,但这是未标准化行为,GCC/Clang 输出格式不同,且结果含空格、模板参数、匿名命名空间等噪音,无法保证编译期可计算(__PRETTY_FUNCTION__ 不是字面量)。
-
__builtin_types_compatible_p只能做类型比较,不能生成字符串 - C++20 的
std::source_location提供文件/函数名,但不提供类型名 - 真正“自动”的方案目前不存在;所有稳定方案都依赖显式特化或外部工具(如反射提案 TS 尚未落地)
如果需要支持大量类型,别硬写特化
手动为几十个类型写特化容易出错且难维护。可行替代路径:
立即学习“C++免费学习笔记(深入)”;
- 用脚本(Python/Perl)解析头文件或 IDL 定义,自动生成
type_name特化代码 - 借助 Clang LibTooling 写一个简单 AST 遍历器,提取类型声明并生成映射表
- 若项目已用 Boost.MPL 或 Boost.Hana,可结合其类型列表和
constexpr if做有限泛化,但依然要枚举类型
真正棘手的不是怎么写第一个特化,而是如何让新增类型自动进入映射——目前没有零成本、标准、纯编译期的通用解法。你得在“完全手动”和“引入构建期代码生成”之间选一个。


















