如何在结构体中存储模板数据类型以调用PubSub注册方法?
我们使用一套基于模板方法的PubSub框架,需通过RegisterTopic<T>(std::string topicName)注册主题,模板参数T用于标识发布/订阅的数据类型。我希望创建主题配置列表存储主题名称与对应数据类型,最初的结构体设计如下:
struct RegistrationTopicType { std::string name; int type; // 需替换为可存储数据类型的机制 };
目标是生成主题列表后批量调用模板注册方法:
std::vector<RegistrationTopicType> topicList = { {"topic1", MyClass}, {"topic2", MyOtherClass}, // 依此类推 }; for (auto & topic : topicList) { RegisterTopic<topic.type>(topic.name); }
我尝试过用模板结构体存储类型:
template<typename T> struct TemplatedRegistrationTopic { using DataType = T; std::string name; };
但实例化后无法将DataType作为模板参数传入RegisterTopic,RegisterTopic<topic.DataType>(topic.name)和Register<topic::DataType>(topic.name)均失败。暂不考虑不同类型主题存入统一列表的问题,请问能否实现“存储数据类型供后续模板方法使用”?另外我不想用枚举+switch方案(如下),因为需维护类型与枚举的映射,违背模板初衷:
enum typelist { Type1, Type2 }; // 每个主题类型对应一个枚举值 struct EnumRegistrationTopicType { std::string name; typelist type; }; std::vector<EnumRegistrationTopicType> enumTopicList = { {"topic1", Type1}, {"topic2", Type2}, // 依此类推 }; for (auto & topic : enumTopicList) { switch (topic.type) { case typelist::Type1: RegisterTopic<MyClass1>(topic.name); break; case typelist::Type2: RegisterTopic<MyClass2>(topic.name); break; } }
可行方案:类型擦除+函数对象封装注册逻辑
核心思路是将“特定类型的注册调用”封装成无类型依赖的函数对象,存入列表后直接遍历执行,绕开模板参数必须为编译期常量的限制。
基础实现
直接用std::function<void()>存储封装好的注册操作:
#include <vector> #include <functional> #include <string> // 假设的PubSub框架注册函数 template<typename T> void RegisterTopic(const std::string& topicName) { // 框架注册逻辑... } class MyClass {}; class MyOtherClass {}; int main() { // 存储批量注册操作 std::vector<std::function<void()>> topicRegistrations = { [](){ RegisterTopic<MyClass>("topic1"); }, [](){ RegisterTopic<MyOtherClass>("topic2"); }, // 可继续添加更多主题 }; // 批量执行注册 for (auto& reg : topicRegistrations) { reg(); } return 0; }
进阶优化:统一管理主题名称与注册逻辑
如果需要同时保留主题名称(用于后续查询等场景),可定义结构体封装:
struct TopicRegistration { std::string name; std::function<void()> registerFunc; }; std::vector<TopicRegistration> topicList = { {"topic1", [](){ RegisterTopic<MyClass>("topic1"); }}, {"topic2", [](){ RegisterTopic<MyOtherClass>("topic2"); }}, }; // 批量注册 for (auto& topic : topicList) { topic.registerFunc(); }
原方案失败原因
模板结构体TemplatedRegistrationTopic<T>的DataType是编译期绑定的类型别名,每个实例化的结构体都是独立类型(比如TemplatedRegistrationTopic<MyClass>与TemplatedRegistrationTopic<MyOtherClass>完全不同),无法存入同一vector。即便绕过存储问题,topic.DataType是运行时对象的成员类型别名,而模板参数要求是编译期可知的常量,因此无法在for循环中直接作为RegisterTopic的模板参数。
内容的提问来源于stack exchange,提问作者gnac

