如何在C++类中创建支持泛型类型的非全局模板map?
解决方案:用类型擦除实现异构全局配置容器
你遇到的问题本质是C容器只能存储同一种类型的对象,而直接声明模板非静态数据成员在C中是不允许的。这里可以用类型擦除的思路解决,既不用把GlobalSettings设为模板类,也能避免void*的不安全设计。
步骤1:定义非模板基类
先创建一个不带模板的抽象基类,作为所有GlobalValue<T>的统一接口:
#pragma once #include <iostream> #include <map> #include <memory> #include <stdexcept> using namespace std; // 非模板基类,提供统一销毁接口 class GlobalValueBase { public: virtual ~GlobalValueBase() = default; // 必须声明虚析构,确保子类对象正确销毁 }; // 模板子类,继承基类实现具体类型存储 template <typename T> class GlobalValue : public GlobalValueBase { public: GlobalValue(const T& value) : value(value) {} T GetValue() const { return value; } void SetValue(T val) { value = val; } private: T value; };
步骤2:实现GlobalSettings类
让GlobalSettings的map存储基类的shared_ptr,再通过模板方法完成类型安全的存取操作:
class GlobalSettings { private: map<string, shared_ptr<GlobalValueBase>> settings_map; // 统一存储基类指针 public: // 设置配置:自动创建对应类型的GlobalValue实例 template <typename T> void SetSetting(const string& key, const T& value) { settings_map[key] = make_shared<GlobalValue<T>>(value); } // 获取配置:检查键存在性与类型匹配性 template <typename T> T GetSetting(const string& key) const { auto it = settings_map.find(key); if (it == settings_map.end()) { throw runtime_error("Key not found: " + key); } // 动态转换到目标类型,类型不匹配时返回空指针 auto val_ptr = dynamic_pointer_cast<GlobalValue<T>>(it->second); if (!val_ptr) { throw runtime_error("Type mismatch for key: " + key); } return val_ptr->GetValue(); } // 更新配置:先验证类型再修改值 template <typename T> void UpdateSetting(const string& key, const T& new_val) { auto it = settings_map.find(key); if (it == settings_map.end()) { throw runtime_error("Key not found: " + key); } auto val_ptr = dynamic_pointer_cast<GlobalValue<T>>(it->second); if (!val_ptr) { throw runtime_error("Type mismatch for key: " + key); } val_ptr->SetValue(new_val); } };
使用示例
int main() { GlobalSettings settings; // 存储不同类型的配置项 settings.SetSetting("window_width", 1920); settings.SetSetting("window_height", 1080); settings.SetSetting("window_title", string("My App")); settings.SetSetting("fullscreen", true); // 获取配置 int width = settings.GetSetting<int>("window_width"); bool fullscreen = settings.GetSetting<bool>("fullscreen"); cout << "Width: " << width << ", Fullscreen: " << boolalpha << fullscreen << endl; // 更新配置 settings.UpdateSetting("window_width", 2560); cout << "Updated width: " << settings.GetSetting<int>("window_width") << endl; // 类型不匹配会抛出异常 try { settings.GetSetting<int>("window_title"); } catch (const runtime_error& e) { cout << "Error: " << e.what() << endl; } return 0; }
核心逻辑说明
- 基类
GlobalValueBase提供统一的类型标识,让map可以容纳任意GlobalValue<T>实例 - 模板方法负责处理类型的创建、转换与校验,
dynamic_pointer_cast会在类型不匹配时返回空指针,我们可以据此抛出异常保证类型安全 - 这种方案既实现了不同类型配置的解耦存储,又无需将
GlobalSettings声明为模板类,用户使用时也不需要提前指定全局类型
内容的提问来源于stack exchange,提问作者orochi
相关产品推荐
相关产品推荐

