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

如何以易读方式处理nlohmann json的type_error异常

问题描述

我用nlohmann json解析config.json文件,该文件会被其他开发者修改。现有代码如下:

try {
        conf.x1 = data.at("x1");
        conf.x2 = data.at("x2");
        // ...
        conf.xN = data.at("xN");
} catch (const nlohmann::json::out_of_range &e) {
        std::cerr << "Error. " << e.what() << std::endl;
        return std::nullopt;
} catch (const nlohmann::json::type_error &e) {
        std::cerr << "Error. " << e.what() << std::endl;
        return std::nullopt;
}

捕获nlohmann::json::out_of_range异常时,e.what()会明确提示缺失的键(比如[json.exception.out_of_range.403] key 'x1' not found),但捕获nlohmann::json::type_error异常时,只能得到类似[json.exception.type_error.302] type must be number, but is string的提示,无法定位具体是哪个配置项类型错误,需要用户逐一排查文件。我曾考虑编写如int read_data(const std::string key)的封装函数,通过模板或多类型函数解决返回值问题,但担心代码复杂化,希望找到类似out_of_range异常提示的简便替代方案。

解决方案

方法1:单个字段解析加局部try-catch

放弃用大try块包裹所有解析逻辑,给每个字段的解析单独添加小范围的try-catch,直接在catch块中明确输出当前出错的键名:

bool parseConfig(const nlohmann::json& data, Config& conf) {
    // 解析x1
    try {
        conf.x1 = data.at("x1");
    } catch (const nlohmann::json::exception& e) {
        std::cerr << "Error with key 'x1': " << e.what() << std::endl;
        return false;
    }

    // 解析x2
    try {
        conf.x2 = data.at("x2");
    } catch (const nlohmann::json::exception& e) {
        std::cerr << "Error with key 'x2': " << e.what() << std::endl;
        return false;
    }

    // 其他字段同理...

    return true;
}

这种方式最直观,代码改动极小,不需要额外封装,每个字段的错误都能精准定位,完全满足需求。

方法2:极简模板封装函数

写一个轻量的模板函数,兼顾复用性和简洁性,自动带上键名信息:

template<typename T>
bool getConfigValue(const nlohmann::json& data, const std::string& key, T& out) {
    try {
        out = data.at(key);
        return true;
    } catch (const nlohmann::json::exception& e) {
        std::cerr << "Error accessing key '" << key << "': " << e.what() << std::endl;
        return false;
    }
}

调用时非常简洁,逻辑清晰:

if (!getConfigValue(data, "x1", conf.x1) || !getConfigValue(data, "x2", conf.x2) /* || 其他字段 */) {
    return std::nullopt;
}

这个模板函数仅做取值和错误提示,代码量小,不会让原有逻辑变得复杂。

方法3:用get_to结合手动类型提示

nlohmann json提供的get_to方法不会抛出异常,而是返回bool表示是否成功。可以结合它手动添加字段和类型信息:

// 先定义一个简单的类型名映射函数
template<typename T>
std::string getFriendlyTypeName() {
    if constexpr (std::is_same_v<T, int>) return "integer";
    else if constexpr (std::is_same_v<T, std::string>) return "string";
    else if constexpr (std::is_same_v<T, double>) return "floating-point number";
    // 根据需要扩展其他类型
    return "unknown type";
}

// 解析示例
if (!data.at("x1").get_to(conf.x1)) {
    std::cerr << "Error parsing key 'x1': expected " << getFriendlyTypeName<decltype(conf.x1)>() << std::endl;
    return std::nullopt;
}

这种方式不需要处理异常,也能精准定位错误字段,类型提示更友好。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 17:45:12