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

如何正确结合std::type_info与std::pair实现多类型向量映射?

解决方案:存储带类型信息的同类型元素向量映射

问题根源

你的代码编译失败的核心原因有两个:

  • std::type_info无法被拷贝或赋值,且引用类型不能作为std::map值的成员(map要求元素可拷贝构造、可赋值)。
  • 调用data["something"]时,map的operator[]会尝试默认构造对应的std::pair,但包含const std::type_info&的pair无法完成默认构造,直接导致编译错误。

另外,用std::vector<std::any>存储同类型元素确实冗余——每个元素都做了类型擦除,既浪费内存也降低效率,完全可以针对“单向量元素类型一致”的约束优化实现。

优化方案一:用std::type_index+std::any包装同类型向量

std::type_index是std::type_info的可拷贝包装类,适合作为容器元素。我们可以用std::any直接存储整个std::vector<T>,而非单个元素,既保留类型信息,又避免冗余:

#include <map>
#include <vector>
#include <any>
#include <typeindex>
#include <string>
#include <stdexcept>

// 定义映射类型:键是列名,值是(同类型向量, 类型索引)
std::map<std::string, std::pair<std::any, std::type_index>> data = {
    {"something", {std::vector<std::string>{}, std::type_index(typeid(std::string))}},
    {"something2", {std::vector<float>{}, std::type_index(typeid(float))}}
};

// 模板函数:向指定列添加元素,自动校验类型匹配
template<typename T>
void push_to_column(std::map<std::string, std::pair<std::any, std::type_index>>& col_map, const std::string& key, T value) {
    auto it = col_map.find(key);
    if (it == col_map.end()) {
        // 列不存在时,自动创建空向量并记录类型
        col_map.emplace(key, std::make_pair(std::vector<T>{}, std::type_index(typeid(T))));
        it = col_map.find(key);
    }

    // 校验类型是否匹配
    if (it->second.second != std::type_index(typeid(T))) {
        throw std::runtime_error("类型不匹配:列" + key + "期望类型与输入类型不一致");
    }

    // 取出向量并添加元素
    auto& vec = std::any_cast<std::vector<T>&>(it->second.first);
    vec.push_back(std::move(value));
}

// 使用示例
int main() {
    push_to_column(data, "something", std::string("hello"));
    // push_to_column(data, "something", 123); // 会抛出异常,类型不匹配
    return 0;
}

优化方案二:自定义类型擦除类(更安全清晰)

针对你的需求,封装一个专门的ColumnData类,把类型检查、向量操作都封装起来,代码可读性和安全性更高:

#include <map>
#include <vector>
#include <memory>
#include <typeindex>
#include <string>
#include <stdexcept>

class ColumnData {
public:
    // 构造函数:传入同类型向量
    template<typename T>
    ColumnData(std::vector<T> vec) 
        : m_type(std::type_index(typeid(T))),
          m_data(std::make_unique<Model<T>>(std::move(vec))) {}

    // 获取列的类型信息(给数据库组件用)
    std::type_index get_type() const { return m_type; }

    // 向列添加元素,自动校验类型
    template<typename T>
    void push_back(T value) {
        if (m_type != std::type_index(typeid(T))) {
            throw std::runtime_error("类型不匹配:列期望类型与输入类型不一致");
        }
        auto* model = dynamic_cast<Model<T>*>(m_data.get());
        if (!model) {
            throw std::runtime_error("类型转换失败");
        }
        model->vec.push_back(std::move(value));
    }

    // 获取列的元素数量
    size_t size() const {
        return m_data->size();
    }

private:
    // 类型擦除的基类
    struct Concept {
        virtual ~Concept() = default;
        virtual size_t size() const = 0;
    };

    // 模板派生类:存储具体类型的向量
    template<typename T>
    struct Model : Concept {
        std::vector<T> vec;
        Model(std::vector<T> v) : vec(std::move(v)) {}
        size_t size() const override { return vec.size(); }
    };

    std::type_index m_type;
    std::unique_ptr<Concept> m_data;
};

// 使用示例
int main() {
    std::map<std::string, ColumnData> data = {
        {"something", ColumnData(std::vector<std::string>{})},
        {"something2", ColumnData(std::vector<float>{})}
    };

    data["something"].push_back(std::string("hello"));
    // data["something"].push_back(123.0f); // 抛出异常,类型不匹配
    return 0;
}

方案对比

  • 方案一实现简单,依赖标准库,适合快速开发。
  • 方案二更面向对象,封装性更好,类型检查更严格,适合大型项目或需要频繁操作列数据的场景。

两种方案都能满足你的需求:数据库组件可以通过std::type_index获取类型信息来创建列,后续也能安全地向列中添加同类型元素。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 20:40:40