如何从std::any提取真实类型并创建对应类型的std::vector?
问题描述
我用std::map<TYPE, std::any>存储枚举TYPE到不同整数类型的映射,因为需要灵活存储多类型数据所以选了std::any。现在想根据key对应的std::any里的真实类型创建该类型的std::vector,但下面的代码编译报错,原因是decltype返回std::any&,没法当vector的模板参数。
示例代码
#include <iostream> #include <any> #include <vector> #include <map> #include <typeinfo> typedef enum TYPE{ INT8=0, INT16=1, INT32=2 } TYPE; int main() { std::map<TYPE, std::any> myMap; myMap[TYPE::INT8] = (int8_t)0; myMap[TYPE::INT16] = (int16_t)0; myMap[TYPE::INT32] = (int32_t)0; std::vector<decltype(myMap[TYPE::INT8])> vec; }
编译错误片段
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/new_allocator.h:63:26: error: forming pointer to reference type 'std::any&' 63 | typedef _Tp* pointer; /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/new_allocator.h:112:7: error: forming pointer to reference type 'std::any&' 112 | allocate(size_type __n, const void* = static_cast<const void*>(0)) /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_vector.h:1293:7: error: 'void std::vector<_Tp, _Alloc>::push_back(value_type&&) [with _Tp = std::any&; _Alloc = std::allocator<std::any&>; value_type = std::any&]' cannot be overloaded with 'void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::any&; _Alloc = std::allocator<std::any&>; value_type = std::any&]' 1293 | push_back(value_type&& __x)
请问怎么实现从std::any中提取真实类型并创建对应类型的std::vector?
解决方案
std::any的核心是类型擦除,编译期无法直接获取它存储的真实类型,必须通过运行时的类型匹配来处理。可以借助std::any_cast结合类型分发的方式实现需求,下面是两种可行的方案:
方案一:基于枚举类型映射确定存储类型
既然TYPE枚举和存储的整数类型是一一对应的,直接通过枚举值分支创建对应类型的vector即可,这种方式简单直接:
#include <iostream> #include <any> #include <vector> #include <map> #include <memory> typedef enum TYPE{ INT8=0, INT16=1, INT32=2 } TYPE; int main() { std::map<TYPE, std::any> myMap; myMap[TYPE::INT8] = (int8_t)0; myMap[TYPE::INT16] = (int16_t)0; myMap[TYPE::INT32] = (int32_t)0; // 用智能指针存储任意类型的vector std::unique_ptr<void> vec_ptr; TYPE target_key = TYPE::INT8; switch(target_key) { case TYPE::INT8: vec_ptr = std::make_unique<std::vector<int8_t>>(); break; case TYPE::INT16: vec_ptr = std::make_unique<std::vector<int16_t>>(); break; case TYPE::INT32: vec_ptr = std::make_unique<std::vector<int32_t>>(); break; default: // 处理未知类型 break; } // 如果需要操作vector,同样需要通过枚举分支做类型转换 if(target_key == TYPE::INT8) { auto& vec = *static_cast<std::vector<int8_t>*>(vec_ptr.get()); vec.push_back(12); std::cout << vec[0] << std::endl; } }
方案二:利用std::any的类型信息动态创建vector
如果枚举和类型的对应关系不固定,或者需要从std::any直接推导类型,可以用std::type_index结合类型映射表,在运行时匹配类型并创建vector:
#include <iostream> #include <any> #include <vector> #include <map> #include <typeindex> #include <functional> #include <memory> typedef enum TYPE{ INT8=0, INT16=1, INT32=2 } TYPE; int main() { std::map<TYPE, std::any> myMap; myMap[TYPE::INT8] = (int8_t)0; myMap[TYPE::INT16] = (int16_t)0; myMap[TYPE::INT32] = (int32_t)0; // 构建类型到vector创建函数的映射 std::map<std::type_index, std::function<std::unique_ptr<void>()>> vec_creators = { {typeid(int8_t), [](){ return std::make_unique<std::vector<int8_t>>(); }}, {typeid(int16_t), [](){ return std::make_unique<std::vector<int16_t>>(); }}, {typeid(int32_t), [](){ return std::make_unique<std::vector<int32_t>>(); }} }; TYPE target_key = TYPE::INT16; auto& any_val = myMap[target_key]; auto type_idx = std::type_index(any_val.type()); // 查找对应的创建函数并生成vector auto it = vec_creators.find(type_idx); if(it != vec_creators.end()) { auto vec_ptr = it->second(); // 操作vector时同样需要类型转换 if(type_idx == typeid(int16_t)) { auto& vec = *static_cast<std::vector<int16_t>*>(vec_ptr.get()); vec.push_back(256); std::cout << vec[0] << std::endl; } } }
关键说明
std::any存储的类型信息只有运行时才能获取,所以无法在编译期直接生成对应类型的vector,必须通过运行时分支或类型映射来处理。- 因为vector的类型是运行时确定的,所以需要用
void*或者智能指针来统一存储,操作时必须通过类型转换还原真实类型。 - 如果业务场景中枚举和类型的对应是固定的,方案一更高效且代码更简洁;如果类型可能动态扩展,方案二更灵活。
内容的提问来源于stack exchange,提问作者ad99
相关产品推荐
相关产品推荐

