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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 05:57:02