如何让C++模板ID生成函数支持含非类型参数的模板?
为模板生成唯一整数ID的通用实现方案
你当前实现的ttypeid函数能为仅接受类型参数的模板(如std::vector、std::map)生成唯一ID,但无法兼容带非类型参数的模板(如std::array)。以下是对应的解决方案:
一、通用实现方式(C++17及以上)
C++17开始允许模板模板参数包含非类型参数,通过调整模板参数声明,可以让ttypeid兼容任意模板类型,包括带非类型参数的模板:
#include <atomic> #include <vector> #include <map> #include <array> #include <iostream> using namespace std; inline unsigned gen_id() { static atomic<unsigned> id = 0; return ++id; } // 支持任意模板模板参数(含类型、非类型参数混合) template <template <typename..., auto...> typename T> inline unsigned ttypeid() { static unsigned id = gen_id(); return id; } // 针对仅含非类型参数的模板补充重载(可选) template <template <auto...> typename T> inline unsigned ttypeid() { static unsigned id = gen_id(); return id; } int main() { cout << ttypeid<vector>() << endl; // 输出1 cout << ttypeid<map>() << endl; // 输出2 cout << ttypeid<array>() << endl; // 输出3,正常编译运行 return 0; }
这个版本通过template <typename..., auto...>的参数声明,同时匹配接受类型参数和非类型参数的模板,完美解决std::array这类模板的兼容问题。
二、兼容旧C++标准的替代方案
如果需要兼容C++17之前的版本,最可行的方案就是你考虑的传入实例化后的占位类型,将模板转为具体类型后再生成ID:
#include <atomic> #include <vector> #include <map> #include <array> #include <iostream> using namespace std; inline unsigned gen_id() { static atomic<unsigned> id = 0; return ++id; } // 针对具体类型生成唯一ID template <typename T> inline unsigned ttypeid() { static unsigned id = gen_id(); return id; } int main() { cout << ttypeid<vector<void>>() << endl; // 输出1 cout << ttypeid<map<void, void>>() << endl; // 输出2 cout << ttypeid<array<void, 0>>() << endl; // 输出3,正常编译运行 return 0; }
这种方式的核心是将模板实例化为占位类型(如vector<void>、array<void, 0>),利用模板特化特性为每个实例化类型生成唯一ID。虽然需要调用者手动传入占位参数,但能兼容所有C++版本,且实现逻辑简单可靠。
内容的提问来源于stack exchange,提问作者Matthew Busche
相关产品推荐
相关产品推荐

