如何正确结合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
相关产品推荐
相关产品推荐

