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

如何使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 11:45:09