nlohmann/json 的 basic_json::get 深度解析:从显式类型转换到零拷贝指针访问
人工智能AI Agent多模态语音AI 应用【免费下载链接】ten-frameworkOpen-source framework for conversational voice AI agents项目地址https://gitcode.com/TEN-framework/ten-framework点击查看免费下载nlohmann::json即basic_json是 TEN Framework 在 C 侧解析、携带与传递 JSON 数据的核心类型其成员函数get()提供了显式类型转换 指针访问两套能力既能把 JSON 值安全地转换为任意兼容的 C 类型如int、std::string、std::vectorshort、std::unordered_map也能零拷贝地直接取到内部存储值的指针。本指南将结合 TEN Framework 仓库中第三方的 nlohmann_json 源码 与该库在 测试用例 中的实际用法把get()的三种重载、模板参数约束、异常行为与底层实现一次讲透让你在 TEN 扩展开发中能正确地读取消息属性、配置项与命令结果。一、总览get()的三副面孔get()在basic_json中有三个公开重载各自服务于不同的使用场景声明如下原文见 get.md// (1) 显式类型转换JSON 值 → 兼容 C 值返回拷贝 templatetypename ValueType ValueType get() const noexcept(...); // (2) 特化转换在当前 basic_json 与其他 basic_json 特化之间转换返回拷贝 templatetypename BasicJsonType BasicJsonType get() const; // (3) 显式指针访问零拷贝取内部存储值返回指针不匹配时返回 nullptr templatetypename PointerType PointerType get_ptr();三个重载的分工非常清晰重载 1值语义把 JSON 值按ValueType转换并返回一个拷贝。这是日常使用最频繁的形态例如j.getstd::string()、j.getint()。重载 2basic_json 特化当目标类型本身就是basic_json的某种特化时直接返回*this的拷贝相当于身份转换identity conversion。重载 3指针语义不做任何转换、不产生拷贝直接返回内部存储值的指针如果请求的指针类型与 JSON 实际类型不匹配则返回nullptr。从源码实现看这三个重载最终统一收敛到一套基于priority_tag的get_impl分派机制见 json.hpp。get()先把模板参数ValueTypeCV用detail::uncvref_t去除引用与 cv 限定得到真正的ValueType然后调用get_implValueType(priority_tag4{})template typename ValueTypeCV, typename ValueType detail::uncvref_tValueTypeCV auto get() const noexcept( noexcept(std::declvalconst basic_json_t().template get_implValueType(detail::priority_tag4 {}))) - decltype(std::declvalconst basic_json_t().template get_implValueType(detail::priority_tag4 {})) { return get_implValueType(detail::priority_tag4 {}); }这里有个值得一提的编译期约束json.hppstatic_assert(!std::is_referenceValueTypeCV::value, get() cannot be used with reference types, you might want to use get_ref());即get()不允许传入引用类型如果你想要引用而非拷贝应当使用配套的get_ref()。这一设计把值语义与引用语义在 API 层面明确切割开。二、重载 1显式类型转换值语义2.1 两条转换路径重载 1 是get()的核心。文档中说明它通过调用json_serializerValueType默认即adl_serializer的from_json()完成转换实际等价于执行ValueType ret; JSONSerializerValueType::from_json(*this, ret); return ret;也就是说getT()本质上是一个先构造、再填充、后返回的三步操作T必须是CopyConstructible 且 DefaultConstructible的类型。不过当T不满足这两个约束时还有一条备用路径直接调用返回值的from_json形态return JSONSerializerValueType::from_json(*this);两条路径的选择由 SFINAE 自动判定路径选择条件等价实现路径 AValueType不是basic_json且json_serializerValueType存在void from_json(const basic_json, ValueType)且不存在ValueType from_json(const basic_json)先构造ValueType ret;再from_json(*this, ret)路径 BValueType不是basic_json且存在ValueType from_json(const basic_json)直接return from_json(*this)文档特别强调若from_json()两种形态同时存在优先选择路径 B直接返回值的那一版。这一规则在源码的get_impl分派中体现为优先级设计——has_non_default_from_json返回ValueType的形态对应priority_tag1优先级高于对应priority_tag0的先构造再填充路径。2.2 底层实现priority_tag 分派在 json.hpp 中路径 A 的实现如下template typename ValueType, detail::enable_if_t detail::is_default_constructibleValueType::value detail::has_from_jsonbasic_json_t, ValueType::value, int 0 ValueType get_impl(detail::priority_tag0 /*unused*/) const noexcept(noexcept( JSONSerializerValueType::from_json(std::declvalconst basic_json_t(), std::declvalValueType()))) { auto ret ValueType(); JSONSerializerValueType::from_json(*this, ret); return ret; }路径 B 对应 json.hpptemplate typename ValueType, detail::enable_if_t detail::has_non_default_from_jsonbasic_json_t, ValueType::value, int 0 ValueType get_impl(detail::priority_tag1 /*unused*/) const noexcept(noexcept( JSONSerializerValueType::from_json(std::declvalconst basic_json_t()))) { return JSONSerializerValueType::from_json(*this); }可以看到noexcept的推导完全取决于from_json()是否可能抛异常——若from_json()抛异常get()也会随之抛出参见下文异常一节。这也是为什么文档在返回值部分强调Depends on whatjson_serializerValueTypefrom_json()method throws。2.3 库内置的 from_json 覆盖范围from_json的基础特化定义在 from_json.hpp覆盖了 TEN 开发中最常用的一批类型空值std::nullptr_t布尔boolean_t即bool字符串string_t即std::string及各种StringType数值number_float_tdouble、number_unsigned_tstd::uint64_t、number_integer_tstd::int64_t以及一般算术类型ArithmeticType枚举EnumType容器std::forward_list、std::valarray、C 数组、std::array、std::vector等任意可构造数组类型对象std::map、std::unordered_map等任意可构造对象类型二进制binary_t元组族std::pair、std::tuple2.4 完整示例与输出官方示例 get__ValueType_const.cpp 展示了同一 JSON 对象向多种类型转换的行为几乎涵盖了上面所有类别#include iostream #include unordered_map #include nlohmann/json.hpp using json nlohmann::json; int main() { // create a JSON value with different types json json_types { {boolean, true}, { number, { {integer, 42}, {floating-point, 17.23} } }, {string, Hello, world!}, {array, {1, 2, 3, 4, 5}}, {null, nullptr} }; // use explicit conversions auto v1 json_types[boolean].template getbool(); auto v2 json_types[number][integer].template getint(); auto v3 json_types[number][integer].template getshort(); auto v4 json_types[number][floating-point].template getfloat(); auto v5 json_types[number][floating-point].template getint(); auto v6 json_types[string].template getstd::string(); auto v7 json_types[array].template getstd::vectorshort(); auto v8 json_types.template getstd::unordered_mapstd::string, json(); ... }对应输出get__ValueType_const.output1 42 42 17.23 17 Hello, world! 1 2 3 4 5 string: Hello, world! number: {floating-point:17.23,integer:42} null: null boolean: true array: [1,2,3,4,5]这个示例点出了三条实战规律浮点数可以转整数17.23转int得到17截断不做四舍五入JSON 数组可以转 STL 容器[1,2,3,4,5]直接转成std::vectorshortJSON 对象可以转关联容器整个对象转成std::unordered_mapstd::string, json其中每个 value 仍是json可以继续用get()或索引下钻。三、重载 2basic_json 特化转换身份语义当目标类型是basic_json的某个特化时get()走特化路径。源码中这一逻辑分成两个优先级json.hpp// priority_tag2转换为另一个 basic_json 特化 template typename BasicJsonType, detail::enable_if_t detail::is_basic_jsonBasicJsonType::value, int 0 BasicJsonType get_impl(detail::priority_tag2 /*unused*/) const { return *this; } // priority_tag3与当前类型完全相同的 basic_json templatetypename BasicJsonType, detail::enable_if_t std::is_sameBasicJsonType, basic_json_t::value, int 0 basic_json get_impl(detail::priority_tag3 /*unused*/) const { return *this; }两者行为一致返回*this的拷贝区别只在于模板约束priority_tag2允许不同的basic_json特化之间互转priority_tag3则限定类型完全一致时走恒等路径。文档中说明这一能力从3.2.0 版本起扩展到其他basic_json特化。从源码结构看这一设计保证了getjson()这样的写法永远安全且零转换成本——它等价于一次拷贝构造复杂度为常量Constant。四、重载 3指针访问零拷贝语义4.1 基本规则重载 3 提供的是显式指针访问直接指向 JSON 值内部存储的那个对象不产生任何拷贝。其约束非常严格PointerType必须是以下类型之一的指针array_t、object_t、string_t、boolean_t、number_integer_t、number_unsigned_t、number_float_t、binary_t。其他类型无法通过编译。get()的指针形态在 json.hpp 中直接委托给get_ptr()templatetypename PointerType, typename std::enable_if std::is_pointerPointerType::value, int::type 0 auto get() noexcept - decltype(std::declvalbasic_json_t().template get_ptrPointerType()) { // delegate the call to get_ptr return get_ptrPointerType(); }而get_ptr()本身又委托给私有的get_impl_ptr()json.hpp。get_impl_ptr为每种内部类型提供一组重载其模式统一为先is_xxx()判型匹配才返回指针否则返回nullptr例如二进制值constexpr const binary_t* get_impl_ptr(const binary_t* /*unused*/) const noexcept { return is_binary() ? m_data.m_value.binary : nullptr; }返回值规则若请求的指针类型与 JSON 内部实际类型匹配返回指向内部存储值的指针若不匹配返回nullptr不做类型转换。4.2 指针稳定性与未定义行为文档用两处醒目标注提醒指针语义的代价指针失效风险源码注释明确the pointer becomes invalid if the underlying JSON object changes——一旦底层 JSON 对象发生修改重新赋值、emplace、容器扩容等之前取得的指针即失效不应再解引用。写入未定义行为原文以 danger 块强调向重载 3 返回的指针所指向的内容写入数据会进入未定义状态undefined behavior。因此指针形态应当只用于读取绝不可当作改写内部值的通道。4.3 完整示例与输出官方示例 get__PointerType.cpp 演示了指针请求的行为#include iostream #include nlohmann/json.hpp using json nlohmann::json; int main() { // create a JSON number json value 17; // explicitly getting pointers auto p1 value.template getconst json::number_integer_t*(); auto p2 value.template getjson::number_integer_t*(); auto p3 value.template getjson::number_integer_t* const(); auto p4 value.template getconst json::number_integer_t* const(); auto p5 value.template getjson::number_float_t*(); // print the pointees std::cout *p1 *p2 *p3 *p4 \n; std::cout std::boolalpha (p5 nullptr) \n; }输出get__PointerType.output17 17 17 17 true要点解读对同一个number_integer_t值const与非const、const限定在指针本身还是指针所指向对象上的四种组合均能取到有效指针解引用结果都是17而请求number_float_t*内部实际存的是整数17时判型失败返回nullptrp5 nullptr输出true——这正是不做类型转换、不匹配即空的体现。五、模板参数与返回值速查模板参数约束含义ValueType任意可转换类型getT()要返回的目标类型BasicJsonType必须是basic_json的特化用于basic_json各特化之间的互转PointerType必须是指向array_t/object_t/string_t/boolean_t/number_integer_t/number_unsigned_t/number_float_t/binary_t的指针指针访问的目标类型其他类型无法编译对应返回值JSON 值转换后的ValueType拷贝*this转换成BasicJsonType后的拷贝指向内部存储值的指针若请求指针类型与值不匹配返回nullptr。六、异常行为get()自身不主动抛异常其异常来源完全取决于from_json()的实现值转换路径若json_serializerValueType::from_json()抛异常例如type_error.302——JSON 类型与目标 C 类型不兼容get()会原样向外传播指针路径get_impl_ptr全部声明为noexcept判型失败返回nullptr不存在异常路径。在实际开发中最常见的异常是nlohmann::json::type_error::create(302, ...)type must be ... but is ...。因此对来源不可控的 JSON如远端消息、配置文件建议先调用is_string()、is_number()等判型方法再执行getT()。TEN 测试工具中的 check.h 正是这一模式的典型实现先is_string()判断字符串走getstd::string()否则整体按 JSON 解析比对。七、在 TEN Framework 中的真实用法TEN Framework 的 C 扩展与集成测试大量使用nlohmann::json的get()。以集成测试 graph_loop_multiple_circle.cc 为例扩展通过send_cmd_and_recv_result收到命令结果后把cmd_result的detail属性解析成nlohmann::json再取total字段并用getstd::string()读出字符串最终std::stoi转成整数参与断言nlohmann::json detail nlohmann::json::parse(cmd_result-get_property_to_json(detail)); EXPECT_EQ((1 2 3) * LOOP_CNT, std::stoi(detail[total].getstd::string()));这条调用链完整呈现了get()在 TEN 消息处理中的标准姿势属性先序列化为 JSON 字符串 →json::parse还原成json→getstd::string()取字段 → 再按需转型。之所以消息属性常用getstd::string()承接是因为跨进程如 msgpack 协议传输后字段多以字符串形式呈现get()恰好提供了与std::string的无缝衔接。另一个佐证来自测试公共头 check.h在断言扩展返回的 JSON 是否等于期望值之前先通过actual.is_string()判型再决定走getstd::string()还是整体json::parse比对——这正是先判型、再 get防御式写法的仓库级范例。八、get 家族get / get_ptr / get_ref / get_to 的选型get()并非唯一的取值入口basic_json还提供get_ptr()、get_ref()、get_to()等兄弟接口同属 json.hpp 的 value access 代码块。它们的关系可归结为一张选型表接口语义拷贝失败行为典型场景getT()值转换是抛异常 / 编译期拒绝需要类型安全转换如getint()、getstd::string()get_ptrT*()指针访问否返回nullptr只读且需要零拷贝访问内部值get_refT()引用访问否抛type_error.303需要引用语义时get()明确禁止引用类型get_to(v)就地写入已有变量否写入传入引用抛异常复用已分配的对象避免临时对象get_ref()的内部实现json.hpp实际就是调get_ptr()空指针则抛type_error::create(303, ...)的封装可见get_ptr()是整个零拷贝取值体系的地基。九、版本演进速览按官方文档的 Version history三个重载的引入时间如下重载 3指针访问自1.0.0起即存在是get家族最古老的成员重载 1值转换自2.1.0引入重载 2basic_json 特化自2.1.0引入3.2.0起扩展支持不同的basic_json特化之间的转换。结语basic_json::get()表面上是一个函数实则是由priority_tag分派串联起来的四个get_impl特化值转换两条路径 basic_json 特化两条路径与指针委托链get→get_ptr→get_impl_ptr共同构成的取值体系。理解它的关键在于记住三条心智模型值语义走from_json、身份语义走拷贝、指针语义走判型委托。在 TEN Framework 的扩展与测试中按先判型、再getT()的方式使用并在追求零拷贝读取时切换到get_ptrT*()同时恪守只读、防失效、防写入三条红线即可安全高效地驾驭 JSON 数据的读取环节。赞分享人工智能AI Agent多模态语音AI 应用【免费下载链接】ten-frameworkOpen-source framework for conversational voice AI agents项目地址https://gitcode.com/TEN-framework/ten-framework点击查看免费下载相关推荐nlohmann::basic_json::get_ref 深度解析JSON for Modern C 零拷贝引用访问指南nlohmann::basic_json::get_ref 深度解析JSON for Modern C 零拷贝引用访问指南 get_refReferen序列化JSON for Modern C 中 basic_json::get() 全面解析显式类型转换与内部存储指针访问JSON for Modern C 中 basic_json::get 全面解析显式类型转换与内部存储指针访问 在 nlohmann/jsonJSON序列化深入解析 nlohmann/json 的 get_ref零拷贝引用访问 JSON 内部值深入解析 nlohmann/json 的 get_ref零拷贝引用访问 JSON 内部值 nlohmann/json JSON for Modern C人工智能AI Agent多模态语音AI 应用上一篇MediaMTX国产化平台实战指南解决流媒体服务器在多架构环境中的部署挑战下一篇如何快速开发Prometheus Operator自定义告警接收器从入门到精通指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

Claude code课程:工具的使用-3.利用工具强制生成 JSON 与 TaoToken 统一 Key 通道

Claude code课程:工具的使用-3.利用工具强制生成 JSON 与 TaoToken 统一 Key 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 2:26:34 阅读更多 →
Meson Snippets 模块实战:用 symbol_visibility_header() 一键生成跨平台符号可见性头文件

Meson Snippets 模块实战:用 symbol_visibility_header() 一键生成跨平台符号可见性头文件

构建工具 【免费下载链接】meson The Meson Build System 项目地址: https://gitcode.com/gh_mirrors/me/meson 点击查看 免费下载 (本文基于当前仓库 docs/markdown/Snippets-module.md,结合 mesonbuild/modules/snippets.py 源码与 test cases/snippe…

2026/10/9 2:26:34 阅读更多 →
AI编程超级能力:Cursor+Claude+Antigravity+Codex工具链实战

AI编程超级能力:Cursor+Claude+Antigravity+Codex工具链实战

1. “Superpowers”不是功能开关,而是AI编程工具链的隐喻性命名体系你搜“superpowers”时,看到的几乎全是Cursor、Claude Code、Antigravity、Codex CLI这些名字——它们没有一个叫“Superpowers”的独立软件,也没有官方发布的“Superpowers…

2026/10/9 2:25:33 阅读更多 →

最新新闻

DeepSeek+Coze AI获客智能体实战:从意图识别到工作流编排

DeepSeek+Coze AI获客智能体实战:从意图识别到工作流编排

简介:这份资源围绕DeepSeek与Coze组合,系统讲解从0到1搭建AI获客智能体的完整流程,面向传统行业中小老板、创业者与个人IP、销售运营人员,帮助解决短视频创作与获客难题。内容涵盖智能体定位与目标、业务流程梳理与痛点分析、场景…

2026/10/9 3:00:51 阅读更多 →
手写SMTP+POP3协议栈:TCP连接与状态机实战

手写SMTP+POP3协议栈:TCP连接与状态机实战

简介:本资源是一套基于Java Web技术实现的模拟邮件系统课程设计项目,面向计算机网络、Web开发初学者及高校课程设计实践者,聚焦SMTP/POP3协议原理与应用,解决邮件收发核心流程的编程实现问题。项目采用MVC架构,以Maven…

2026/10/9 3:00:51 阅读更多 →
Kanban:自托管的个人计划与待办看板

Kanban:自托管的个人计划与待办看板

项目仓库: https://github.com/Akvicor/kanban桌面客户端: https://github.com/Akvicor/kanban-app个人博客: https://www.ksyaki.com/archives/kanban-zi-tuo-guan-de-ge-ren-ji-hua-yu-dai-ban-kan-ban Docker 镜像: ghcr.io/akvicor/kanban Kanban 是一个自托管的个人看板…

2026/10/9 3:00:51 阅读更多 →
LmyExamExport.rar:.NET考试数据Excel导出中间件实战指南

LmyExamExport.rar:.NET考试数据Excel导出中间件实战指南

简介:这是一款面向高校教师与教育信息化开发者的蓝墨云试题导出工具,解决平台仅支持导入、无法导出试题数据的痛点,支持将蓝墨云测试数据解析为结构化试题库,并可选是否显示答案,适用于教学资源归档、试卷复用及学生自…

2026/10/9 3:00:51 阅读更多 →
信道估计数据集使用全攻略:从解压到PyTorch加载与避坑

信道估计数据集使用全攻略:从解压到PyTorch加载与避坑

简介:信道估计是无线通信系统接收端的关键环节,准确估计信道响应可显著提升数据传输性能。这份压缩包面向通信工程研究者与相关专业学生,整合了LS与MMSE两类经典估计算法的MATLAB实现,以及信道估计、均衡前后效果、LS与MMSE性能对…

2026/10/9 3:00:51 阅读更多 →
华为设备引导加载程序解锁工具实战:从驱动环境到解锁码写入的完整链路

华为设备引导加载程序解锁工具实战:从驱动环境到解锁码写入的完整链路

1. 解锁工具到底在解决什么问题第一次接触手机解锁工具的人,脑子里往往有个模糊的印象:插上数据线、点一下按钮,锁就开了。实际远没有这么简单。所谓“解锁”,在不同语境下指向完全不同的操作——有的是解除运营商网络锁&#xff…

2026/10/9 2:59:51 阅读更多 →

日新闻

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API这个话题,隔三差五就会在群里被翻出来讨论一次。上周还有个同事线上处理一个订单超时问题,排查到最后发现是ZonedDateTime序列化后时区丢了,用户在下单当天晚上看到的时间整整差了8个小时。这类问题几乎每个做Java开发的人都遇到过…

2026/10/9 0:00:49 阅读更多 →
EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

前几个月我手头有好几台机器需要互相访问:办公室台式机、家里 NAS、还有一台云主机。如果只是偶尔传个文件倒还好,问题是工作场景经常要在几处环境之间来回切换,每次都先登录跳板机再层层代理,实在折腾。我先后试过端口映射、自建…

2026/10/9 0:00:49 阅读更多 →
AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent 这个词在过去一年里被反复提及,但真正动手搭过一套能跑起来的 Agent 系统的人都知道,从"知道它是什么"到"让它稳定干活"之间隔着一整套工程决策。我前后参与过几个 Agent 项目的落地,从最初用现成框架拼装&…

2026/10/9 0:01:50 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:40 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 10:10:36 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 21:13:17 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 13:34:55 阅读更多 →