如何使用Cereal反序列化无键值对包裹的JSON数组
问题原因
Cereal的JSON输入归档(cereal::JSONInputArchive)设计上默认要求JSON的顶级元素是对象结构(键值对),而非数组。当你传入[1,2,3]这种顶级数组时,归档内部会调用RapidJSON的IsObject()断言,断言失败就抛出cereal::RapidJSONException异常。
解决方案
方案1:临时包装JSON字符串(最简单)
把原始数组JSON包裹成带键的对象结构,再用Cereal指定键名反序列化。
#include <cassert> #include <iostream> #include <sstream> #include <cereal/archives/json.hpp> #include <cereal/types/vector.hpp> #include <string> int main() { std::string original_json = "[1,2,3]"; // 将数组包装为带键的JSON对象 std::string wrapped_json = "{\"target_vec\": " + original_json + "}"; std::stringstream ss(wrapped_json); cereal::JSONInputArchive ar(ss); std::vector<int> vec; // 指定键名匹配包装后的JSON结构 ar(cereal::make_nvp("target_vec", vec)); assert(vec.size() == 3); std::cout << vec[0] << ", " << vec[1] << ", " << vec[2] << std::endl; return 0; }
方案2:直接操作RapidJSON解析数组(不修改原始JSON)
既然Cereal底层依赖RapidJSON,可直接用RapidJSON解析原始数组,再填充到std::vector中——这种方法无需修改原始JSON字符串,适合无法修改API响应的场景。
#include <cassert> #include <iostream> #include <sstream> #include <cereal/types/vector.hpp> #include <rapidjson/document.h> int main() { std::stringstream ss("[1,2,3]"); std::string json_str; ss >> json_str; // 用RapidJSON直接解析数组 rapidjson::Document doc; doc.Parse(json_str.c_str()); assert(doc.IsArray()); std::vector<int> vec; vec.reserve(doc.Size()); for (const auto& elem : doc.GetArray()) { vec.push_back(elem.GetInt()); } assert(vec.size() == 3); std::cout << vec[0] << ", " << vec[1] << ", " << vec[2] << std::endl; return 0; }
方案3:自定义包装类适配Cereal归档(适合复杂类型)
如果需要用Cereal处理更复杂的数组元素(而非简单int),可以定义一个包装类,编写自定义的反序列化逻辑,直接处理顶级数组:
#include <cassert> #include <iostream> #include <sstream> #include <cereal/archives/json.hpp> #include <cereal/types/vector.hpp> struct ArrayWrapper { std::vector<int> data; template <typename Archive> void load(Archive& ar) { // 获取归档对应的RapidJSON Value auto& json_val = ar.getSharedValue(); assert(json_val.IsArray()); data.reserve(json_val.Size()); for (const auto& elem : json_val.GetArray()) { int val; // 为数组元素创建临时归档反序列化 cereal::JSONInputArchive elem_ar(elem); elem_ar(val); data.push_back(val); } } }; int main() { std::stringstream ss("[1,2,3]"); cereal::JSONInputArchive ar(ss); ArrayWrapper wrapper; ar(wrapper); assert(wrapper.data.size() == 3); std::cout << wrapper.data[0] << ", " << wrapper.data[1] << ", " << wrapper.data[2] << std::endl; return 0; }
注意:
getSharedValue()属于Cereal的内部接口,不同版本可能存在兼容性问题,使用前需确认你的Cereal版本支持该方法。
内容的提问来源于stack exchange,提问作者pptaszni
相关产品推荐
相关产品推荐

