C++如何在编译期实现无需手动注册的顺序递增类型ID分配
方案验证
你当前用模板实例的函数地址作为类型唯一标识的方案是可行的:每个不同类型实例化的GetUniqueTypeValue<T>::get都是独立函数,地址全局唯一,不存在冲突问题。
编译期自动递增类型ID实现
你需要的无手动注册、编译期自动分配递增ID的功能,可以基于C++20的模板元编程特性实现,核心思路是利用ADL(参数依赖查找)和友元函数的实例化状态来实现编译期计数器,代码如下:
核心实现代码
// 编译期计数器基础组件 template <int N> struct Tag { friend constexpr int adl_counter(Tag<N>); }; template <int N> struct Writer { friend constexpr int adl_counter(Tag<N>) { return N; } static constexpr int value = N; }; template <int N = 0, auto = adl_counter(Tag<N>{})> constexpr int next_id(int) { return next_id<N + 1>(0); } template <int N = 0> constexpr int next_id(float) { return Writer<N>::value; } // 类型ID接口,每个类型对应唯一的递增编译期ID template <typename T> inline constexpr int type_id = next_id(0);
测试示例
// 编译期即可拿到ID值 constexpr int int_id = type_id<int>; // 输出0 constexpr int float_id = type_id<float>; // 输出1 constexpr int double_id = type_id<double>; // 输出2 constexpr int int_id_dup = type_id<int>; // 输出0,同一类型ID保持一致 int main() { static_assert(int_id == 0); static_assert(float_id == 1); static_assert(double_id == 2); static_assert(int_id_dup == int_id); return 0; }
注意事项
- 上述实现依赖C20标准,若需要兼容C17可以调整非类型模板参数的写法,核心逻辑基本一致。
- 单编译单元下ID的分配顺序和你首次实例化
type_id<T>的顺序完全一致;如果需要跨编译单元保证ID顺序统一,这个方案不适用,需要补充预注册逻辑,或者保证所有类型的type_id首次实例化都在同一个编译单元内。 - 如果你需要把ID转为
void*类型适配你现有sequentialise函数的接口,直接reinterpret_cast<void*>(static_cast<uintptr_t>(type_id<T>))即可,编译期也可以完成转换。
内容的提问来源于stack exchange,提问作者Zebrafish
相关产品推荐
相关产品推荐

