如何从列表/映射自动生成条件表达式?
嘿,这种靠一堆if-else分支来匹配类型名创建对象的写法,类型少的时候还好,一旦类型多起来,不仅代码臃肿,维护起来也超麻烦!我给你几个更优雅的解决方案,帮你摆脱这种“面条代码”~
方案1:使用类型注册表(最通用的解法)
核心思路是把类型名到初始化逻辑的映射放到一个std::map里,替代冗长的if-else链。假设你的所有对象都继承自一个公共基类(毕竟std::vector需要存储同类型元素,智能指针是常见选择),代码示例如下:
// 定义所有对象的公共基类 class Base { public: virtual ~Base() = default; // 这里可以添加对象的公共接口 }; // 具体对象类型 class FooObject : public Base { /* 你的类实现 */ }; class BarObject : public Base { /* 你的类实现 */ }; class Object3 : public Base { /* 你的类实现 */ }; // 原有的初始化模板函数保持不变 template<typename T> void initItem(std::vector<std::unique_ptr<Base>>& itemList) { itemList.emplace_back(std::make_unique<T>()); // 这里可以添加T类型对象的专属初始化逻辑 } // 建立类型名到初始化函数的注册表 std::map<std::string, std::function<void(std::vector<std::unique_ptr<Base>>&)>> itemRegistry = { {"foo", [](auto& list) { initItem<FooObject>(list); }}, {"bar", [](auto& list) { initItem<BarObject>(list); }}, {"baz", [](auto& list) { initItem<Object3>(list); }} // 新增类型时,只需要在这里追加一行映射即可 }; // 调用逻辑简化成这样 std::string name = /* 来自你的类型列表的元素 */; std::vector<std::unique_ptr<Base>> itemList; auto it = itemRegistry.find(name); if (it != itemRegistry.end()) { it->second(itemList); // 直接调用对应的初始化逻辑 } else { // 处理未知类型的情况,比如打印错误日志 std::cerr << "Unknown item type: " << name << std::endl; }
这个方案的好处很明显:
- 符合开闭原则,新增类型不需要修改原有逻辑,只需要添加注册表项
- 代码结构更清晰,类型映射关系一目了然
- 后期维护成本大幅降低
方案2:无多态场景的std::variant方案
如果你的对象不需要多态(即不需要通过基类指针统一调用接口),可以用std::variant来存储不同类型的对象,注册表的写法也类似:
#include <variant> // 定义变体类型,包含所有可能的对象类型 using ItemVariant = std::variant<FooObject, BarObject, Object3>; // 注册表直接映射到变体对象的构造 std::map<std::string, std::function<void(std::vector<ItemVariant>&)>> variantRegistry = { {"foo", [](auto& list) { list.emplace_back(FooObject{}); }}, {"bar", [](auto& list) { list.emplace_back(BarObject{}); }}, {"baz", [](auto& list) { list.emplace_back(Object3{}); }} }; // 调用逻辑 std::vector<ItemVariant> itemList; auto it = variantRegistry.find(name); if (it != variantRegistry.end()) { it->second(itemList); }
这种方式省去了基类的定义,适合不需要多态的简单场景。
进阶优化:自动注册类型(无需手动维护注册表)
如果你的类型非常多,甚至每个类型都在单独的文件里,可以用静态注册的方式,让每个类型自己注册到注册表中,完全不用手动维护映射列表:
// 全局注册表(用单例模式确保唯一实例) auto& getItemRegistry() { static std::map<std::string, std::function<void(std::vector<std::unique_ptr<Base>>&)>> registry; return registry; } // 注册辅助模板 template<typename T> struct ItemRegistrar { ItemRegistrar(const std::string& typeName) { getItemRegistry()[typeName] = [](auto& list) { initItem<T>(list); }; } }; // 在每个具体类型的.cpp文件中添加静态注册代码 // FooObject.cpp static ItemRegistrar<FooObject> fooRegistrar("foo"); // BarObject.cpp static ItemRegistrar<BarObject> barRegistrar("bar"); // Object3.cpp static ItemRegistrar<Object3> bazRegistrar("baz");
这样一来,新增类型时只需要在自己的实现文件里加一行注册代码,连注册表的定义都不用碰,扩展性拉满!
内容的提问来源于stack exchange,提问作者goaran
相关产品推荐
相关产品推荐

