如何读写含boost::any的std::map至XML/JSON?现状咨询
现在完全可以实现!
10年前的说法没错,那时候boost::any本身没有内置的序列化支持,类型擦除后很难追踪原始类型来完成反序列化。但现在借助boost::serialization库,我们可以扩展boost::any的序列化能力,轻松实现你的需求。
核心思路
boost::any的本质是类型擦除,所以序列化时需要两步:
- 先把存储值的类型信息写入文件
- 再根据类型信息提取对应的值并序列化
反序列化时则反过来:先读取类型信息,再根据类型读取对应的值,重新构造boost::any对象。
具体实现步骤
1. 引入必要依赖
首先确保你已经安装了Boost库,然后包含这些头文件:
#include <map> #include <string> #include <fstream> #include <boost/any.hpp> #include <boost/serialization/access.hpp> #include <boost/serialization/map.hpp> #include <boost/archive/text_oarchive.hpp> #include <boost/archive/text_iarchive.hpp> #include <boost/serialization/string.hpp>
2. 扩展boost::any的序列化支持
我们需要给boost::any特化boost::serialization::serialize模板,让序列化库知道怎么处理它:
namespace boost { namespace serialization { template<class Archive> void serialize(Archive& ar, boost::any& any_val, const unsigned int version) { // 先序列化类型名称(用来识别原始类型) const std::type_info* type_ptr = any_val.type(); ar << type_ptr->name(); // 根据类型匹配,提取值并序列化 if (type_ptr == &typeid(int)) { int val = boost::any_cast<int>(any_val); ar << val; } else if (type_ptr == &typeid(std::string)) { std::string val = boost::any_cast<std::string>(any_val); ar << val; } else if (type_ptr == &typeid(double)) { double val = boost::any_cast<double>(any_val); ar << val; } // 这里可以继续添加你需要支持的其他类型,比如bool、float、自定义结构体等 // 如果是自定义类型,要确保该类型也实现了boost序列化支持 } } // namespace serialization } // namespace boost
3. 编写写入文件的函数
用boost::archive::text_oarchive(文本格式,可读性强)来序列化整个map:
void write_data_map(const std::map<const std::string, boost::any>& data, const std::string& file_path) { std::ofstream output_file(file_path); boost::archive::text_oarchive archive(output_file); // 注意:如果你的编译器对const key的map序列化有警告,可以把map声明改成std::map<std::string, boost::any> // 因为map的key本身就是不可修改的,外部加const其实没必要 archive << data; }
4. 编写读取文件的函数
用boost::archive::text_iarchive来反序列化,恢复原始的map和数据类型:
void read_data_map(std::map<const std::string, boost::any>& data, const std::string& file_path) { std::ifstream input_file(file_path); boost::archive::text_iarchive archive(input_file); archive >> data; }
注意事项
- 类型扩展:上面的示例只支持了int、string、double三种类型,你需要根据自己的业务需求添加更多类型支持。如果是自定义类型,需要给该类型也实现
boost::serialization的serialize函数。 - 归档格式:除了文本归档,你还可以用
boost::archive::binary_oarchive/binary_iarchive,这种格式更紧凑、高效,适合大数据场景。 - map的key:如果遇到
const std::string作为key的序列化问题,直接改成std::string即可——map容器内部的key本来就是const的,外部的const修饰不会影响功能。
测试示例
int main() { std::map<const std::string, boost::any> my_data; my_data["age"] = 28; my_data["name"] = std::string("Alice"); my_data["height"] = 1.75; // 写入文件 write_data_map(my_data, "data.txt"); // 清空map,测试读取 my_data.clear(); read_data_map(my_data, "data.txt"); // 验证类型和值 std::cout << "Age: " << boost::any_cast<int>(my_data["age"]) << std::endl; std::cout << "Name: " << boost::any_cast<std::string>(my_data["name"]) << std::endl; std::cout << "Height: " << boost::any_cast<double>(my_data["height"]) << std::endl; return 0; }
这个测试代码会把数据写入data.txt,然后读取回来,输出的类型和值和原始完全一致。
内容的提问来源于stack exchange,提问作者rednefed
相关产品推荐
相关产品推荐

