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

nlohmann-json序列化std::optional时to_json编译错误问题

std::optional适配nlohmann-json序列化编译错误修复

问题现象

需要基于nlohmann-json库实现std::optional<T>类型的序列化与反序列化,参考官方boost::optional适配示例编写的逻辑存在单边异常:

  • 反序列化(from_json)功能可正常运行,断点可正常命中
  • 序列化(to_json)相关逻辑在MSVC环境下无法编译通过

最小复现代码

// OptionalSeriealisationTest.cpp 
//#define JSON_USE_IMPLICIT_CONVERSIONS 0 
// 曾尝试按issue讨论切换该宏开关,无效果

#include <iostream>
#include <optional>
#include <nlohmann/json.hpp>
namespace nlohmann
{
    template <typename T>
    struct adl_serializer<std::optional<T>>
    {
        // 序列化逻辑为报错根源
        static void to_json(json& j, const std::optional<T>& opt) {
            if (opt)
            {
                j = opt.value();
            }
            else
            {
                j = nullptr;
            }
        }

        static void from_json(const json& j, std::optional<T>& opt) {
            if (j.is_null()) {
                opt = std::nullopt;
            }
            else {
                opt = j.get<T>();
            }
        }
    };
}

using json = nlohmann::ordered_json;

int main()
{
    {
        // 反序列化正常值:可正常运行
        json j;
        j["x"] = 4.0f;
        std::optional<float> x;
        j.at("x").get_to<std::optional<float>>(x);
        std::cout <<  x.has_value() << std::endl;
        std::cout << x.value() << std::endl;
    }

    {
        // 反序列化空值:可正常运行
        json j;
        j["x"] = nullptr;
        std::optional<float> x = 4.0f;
        j.at("x").get_to<std::optional<float>>(x);
        std::cout << x.has_value() << std::endl;
    }

    {
        // 编译报错
        std::optional<float> x = 4.0;
        json j;
        j["x"] = x; 
    }

    {
        // 编译报错
        std::optional<float> x = 4.0;
        auto j = json({ "x", x });
    }

}

MSVC编译报错

Error E0289: no instance of constructor "nlohmann::basic_json<...>::basic_json" matches the argument list
[with ObjectType=nlohmann::ordered_map, ArrayType=std::vector,
StringType=std::string, BooleanType=bool, NumberIntegerType=int64_t,
NumberUnsignedType=uint64_t, NumberFloatType=double,
AllocatorType=std::allocator, JSONSerializer=nlohmann::adl_serializer,
BinaryType=std::vector<uint8_t, std::allocator<uint8_t>>]

错误原因

核心问题是adl_serializer特化时绑定的json类型,与实际使用的json类型不匹配:

  1. 你在nlohmann命名空间内编写特化逻辑时,函数参数里写的json是库默认提供的nlohmann::json类型——即basic_json使用默认模板参数(对象存储用std::map)的实例化版本。
  2. 你的代码里实际用的是nlohmann::ordered_json,这是basic_json使用ordered_map作为对象存储的另一个独立实例化类型,和默认的nlohmann::json是完全不同的类型。
  3. 官方boost::optional示例全程使用默认的nlohmann::json类型,不存在类型不匹配问题,因此可以正常编译。
  4. 反序列化逻辑看似正常运行,是因为反序列化调用路径上的模板推导触发了隐式转换,刚好可以命中你写的特化逻辑;但序列化时的赋值操作要求参数类型精确匹配,找不到对应to_json重载时,编译器会尝试直接用std::optional<float>构造json对象,最终触发“无匹配构造函数”的错误。

修复方案

推荐使用通用写法,不硬编码具体json类型,让特化逻辑兼容所有basic_json实例(包括默认json、ordered_json和自定义参数的basic_json),修正后的adl_serializer代码如下:

namespace nlohmann
{
    template <typename T>
    struct adl_serializer<std::optional<T>>
    {
        template<typename JsonType>
        static void to_json(JsonType& j, const std::optional<T>& opt) {
            if (opt.has_value()) {
                j = *opt;
            } else {
                j = nullptr;
            }
        }

        template<typename JsonType>
        static void from_json(const JsonType& j, std::optional<T>& opt) {
            if (j.is_null()) {
                opt = std::nullopt;
            } else {
                opt = j.template get<T>();
            }
        }
    };
}

替换原有特化代码后即可正常编译运行,无需修改其他业务逻辑。
如果你的项目里只会使用ordered_json一种json类型,也可以直接把特化逻辑里的json参数类型替换为nlohmann::ordered_json,但这种写法通用性差,不推荐。


内容的提问来源于stack exchange,提问作者AcountForDaftQuestions

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 17:12:32