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

C++编译期收集模板方法已实例化类型并实现编译期存在性判断

实现方案

C++ 标准没有内置查询模板实例化记录的原生能力,但可以通过**有状态元编程(友元注入+ADL查找)**的技巧实现编译期动态增长的类型列表,完全满足你需要的实例化状态检查需求。


完整可运行代码

#include <cstdio>
#include <type_traits>

// 基础类型标记结构
template <typename T>
struct type_tag { using type = T; };

struct A {
  template <typename T>
  void bar(const T&) {
    // 编译期检查当前类型是否已经被注册过
    if constexpr (requires { registered(type_tag<T>{}); }) {
      // 类型已实例化过的处理逻辑
      puts("当前类型已处理");
    } else {
      // 类型首次实例化的处理逻辑,同时注入探针函数完成注册
      friend auto registered(type_tag<T>) { return true; }
      puts("当前类型首次处理");
    }
  }
};

// 测试用自定义类型
struct Msg1 {};
struct Msg2 {};

int main() {
  A a;
  a.bar(Msg1{}); // 输出:当前类型首次处理
  a.bar(Msg1{}); // 输出:当前类型已处理
  a.bar(Msg2{}); // 输出:当前类型首次处理
  a.bar(Msg2{}); // 输出:当前类型已处理
  return 0;
}

逻辑说明

  • 第一次用某类型T调用bar时,requires表达式检测不到对应的registered探针函数,进入首次处理分支,通过友元声明将对应T的registered函数注入到外层命名空间,完成类型注册。
  • 后续再用同类型T调用bar时,requires表达式可以直接找到已经注入的探针函数,进入已处理分支。
  • 所有注入的探针函数会在编译期留存,相当于你需要的动态增长typelist,额外增加编译期索引遍历逻辑就可以导出所有已实例化的T组成的完整类型列表。

注意事项

  • 该技巧支持C17及以上标准,C20明确了其合法性,主流编译器(GCC、Clang、MSVC)均兼容。
  • 单翻译单元下使用无额外问题,跨翻译单元共享实例化状态需要额外做全局声明处理。

内容的提问来源于stack exchange,提问作者Juergen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 23:48:00