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

如何从字符串类型名称构建模板类(如std::map)?

从字符串类型描述实例化模板类的解决方案

C++是静态强类型语言,没法直接通过运行时字符串动态推导typename并实例化模板,必须提前把需要支持的类型做显式映射,用工厂模式结合类型分发来实现你的需求。以下是针对你场景的具体实现方案:

1. 建立字符串到目标类型的映射

先把XML里可能出现的类型字符串(比如"int32_t"、"float")和对应的C++标量类型做绑定,方便后续匹配:

#include <unordered_map>
#include <stdexcept>

enum class ScalarType {
    Int32,
    Int64,
    Float,
    Double
};

// 字符串到类型枚举的映射表
std::unordered_map<std::string, ScalarType> type_str_map = {
    {"int32_t", ScalarType::Int32},
    {"int64_t", ScalarType::Int64},
    {"float", ScalarType::Float},
    {"double", ScalarType::Double}
};

2. 实现封装模板类

以你需要的std::map<std::string, unique_ptr<T>>封装为例,编写模板类:

#include <map>
#include <memory>
#include <string>

template<typename T>
class MapWrapper {
private:
    std::map<std::string, std::unique_ptr<T>> data_map;
public:
    // 示例:添加键值对
    void add(const std::string& key, T value) {
        data_map[key] = std::make_unique<T>(std::move(value));
    }

    // 示例:获取值(返回指针,不存在则为nullptr)
    T* get(const std::string& key) {
        auto it = data_map.find(key);
        return it != data_map.end() ? it->second.get() : nullptr;
    }

    // 可添加你需要的其他业务处理方法
};

3. 编写工厂函数生成对应模板实例

不同类型的MapWrapper<T>是完全独立的类型,用std::variant统一存储这些实例,通过工厂函数根据字符串返回对应实例:

#include <variant>

// 用variant存储所有支持的MapWrapper实例类型
using WrapperVariant = std::variant<
    std::unique_ptr<MapWrapper<int32_t>>,
    std::unique_ptr<MapWrapper<int64_t>>,
    std::unique_ptr<MapWrapper<float>>,
    std::unique_ptr<MapWrapper<double>>
>;

WrapperVariant create_map_wrapper(const std::string& type_str) {
    auto type_it = type_str_map.find(type_str);
    if (type_it == type_str_map.end()) {
        throw std::invalid_argument("不支持的类型: " + type_str);
    }

    switch (type_it->second) {
        case ScalarType::Int32:
            return std::make_unique<MapWrapper<int32_t>>();
        case ScalarType::Int64:
            return std::make_unique<MapWrapper<int64_t>>();
        case ScalarType::Float:
            return std::make_unique<MapWrapper<float>>();
        case ScalarType::Double:
            return std::make_unique<MapWrapper<double>>();
        default:
            throw std::invalid_argument("无效类型");
    }
}

4. 使用示例(从XML读取类型后实例化)

读取XML中的类型字符串后,调用工厂函数生成实例,再用std::visit操作variant中的具体对象:

#include <iostream>

int main() {
    // 模拟从XML读取到的类型字符串
    std::string xml_type = "float";
    try {
        auto wrapper = create_map_wrapper(xml_type);

        // 用std::visit访问variant里的具体实例
        std::visit([](auto& wrapper_ptr) {
            wrapper_ptr->add("temperature", 25.6f);
            auto temp = wrapper_ptr->get("temperature");
            if (temp) {
                std::cout << "读取到温度: " << *temp << std::endl;
            }
        }, wrapper);
    } catch (const std::exception& e) {
        std::cerr << "错误: " << e.what() << std::endl;
    }
    return 0;
}

扩展说明

  • 如果后续需要支持更多类型,只需在枚举、映射表、WrapperVariant和switch分支中添加对应类型即可。
  • 这种方式本质是提前枚举所有可能用到的类型,因为C++模板是编译期实例化的,无法在运行时凭空生成新的模板实例。
  • 若不想用std::variant,也可以采用抽象基类+派生类的方式:定义纯虚基类,让每个MapWrapper<T>继承它,工厂函数返回基类指针,但这种方式需要把所有业务方法声明为虚函数,灵活性稍弱。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 08:24:19