ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

JSON_HAS_CPP_11/14/17/20/23/26 宏详解:nlohmann/json 如何检测并强制指定 C++ 语言标准

JSON_HAS_CPP_11/14/17/20/23/26 宏详解:nlohmann/json 如何检测并强制指定 C++ 语言标准 JSON_HAS_CPP_11/14/17/20/23/26 宏详解nlohmann/json 如何检测并强制指定 C 语言标准【免费下载链接】jsonJSON for Modern C项目地址: https://gitcode.com/GitHub_Trending/js/jsonnlohmann/jsonJSON for Modern C以 C11 为最低基线但对 C17、C20、C23 乃至 C26 的新特性提供了渐进式支持。本文聚焦该库的JSON_HAS_CPP_11、JSON_HAS_CPP_14、JSON_HAS_CPP_17、JSON_HAS_CPP_20、JSON_HAS_CPP_23、JSON_HAS_CPP_26六个预处理器宏结合源码讲解它们如何被自动检测、在库中扮演什么角色以及何时需要开发者手动覆盖、如何正确覆盖。读完你将掌握这套「C 标准开关」的使用场景与边界能够在编译器特性检测不准时可靠地驱动 nlohmann/json 的条件编译行为。宏的用途一套贯穿全库的标准版本开关这些宏并不存在于公开 API 中而是库内部实现 C 标准特性条件编译的“总闸”。nlohmann/json 本身是 header-only 且面向 C11 编译的但对后续标准引入的库组件提供了可选支持例如C14泛型 lambda、std::index_sequence等元编程基础见 detail/meta/cpp_future.hpp 与 ordered_map.hpp 中的#ifdef JSON_HAS_CPP_14分支C17std::string_view、std::optional、std::filesystem对应 json_has_filesystem 宏体系C20concepts、三路比较、std::format、std::rangesC26std::is_trivial被弃用后改用std::is_trivially_copyable等特性的兼容处理。对这类新增特性库会通过预处理器判断当前使用的 C 标准。六个宏的声明原型如下#define JSON_HAS_CPP_11 #define JSON_HAS_CPP_14 #define JSON_HAS_CPP_17 #define JSON_HAS_CPP_20 #define JSON_HAS_CPP_23 #define JSON_HAS_CPP_26一旦开发者手动定义了其中任意一个宏库内置的“自动检测”将被整体跳过并以开发者提供的 C 版本为准无条件假设。这一机制对“只实现了标准的一部分、会被检测逻辑误判”的编译器尤其有用。默认检测逻辑__cplusplus、_MSVC_LANG与_HAS_CXX17在开发者未手动定义任何JSON_HAS_CPP_*宏时库依据编译器的标准版本宏自动完成检测涉及的主要宏包括__cplusplus、_MSVC_LANGMSVC 在未完全遵循__cplusplus时使用、_HAS_CXX17与_HAS_CXX14。完整的检测算法位于 include/nlohmann/detail/macro_scope.hpp 的头部约第 33–59 行采用“由高到低”的阶梯式判断一旦某个更高的标准阈值成立就把从该标准向下到 C14 的所有宏一次性定义齐判定条件满足其一自动定义的宏__cplusplus 202302L或_MSVC_LANG 202302LJSON_HAS_CPP_26、JSON_HAS_CPP_23、JSON_HAS_CPP_20、JSON_HAS_CPP_17、JSON_HAS_CPP_14__cplusplus 202002L或_MSVC_LANG 202002LJSON_HAS_CPP_23、JSON_HAS_CPP_20、JSON_HAS_CPP_17、JSON_HAS_CPP_14__cplusplus 201703L或_MSVC_LANG 201703LJSON_HAS_CPP_20、JSON_HAS_CPP_17、JSON_HAS_CPP_14__cplusplus 201402L或_HAS_CXX17 1JSON_HAS_CPP_17、JSON_HAS_CPP_14__cplusplus 201103L或_HAS_CXX14 1JSON_HAS_CPP_14检测结束后无论命中哪一档JSON_HAS_CPP_11都会被无条件定义——因为 C11 是库支持的最低编译标准// the cpp 11 flag is always specified because it is the minimal required version #define JSON_HAS_CPP_11源码中一个值得注意的实现细节是_HAS_CXX17分支处标注了// fix for issue #464部分 MSVC 环境下仅依据__cplusplus会误判 C17 支持情况因此库额外读取 MSVC 的_HAS_CXX17宏来修正该问题。这也正是“编译器只实现了标准的一部分、导致检测不准”这一真实场景的例证。六个宏在源码中的实际作用点了解了宏的定义方式后再看它们在核心实现中的消费方式可以更清楚手动覆盖会影响到哪些能力。C17 相关std::string_view与std::optional主头文件 include/nlohmann/json.hpp 在第 75–80 行通过#if defined(JSON_HAS_CPP_17)决定是否引入string_view以及在启用静态 RTTI 时的any#if defined(JSON_HAS_CPP_17) #if JSON_HAS_STATIC_RTTI #include any #endif #include string_view #endif与此同时detail/conversions/from_json.hpp 在第 35–71 行依据#ifdef JSON_HAS_CPP_17才定义std::optionalT的反序列化转换——JSONnull映射到std::nullopt、非空值则emplace出T#ifdef JSON_HAS_CPP_17 template typename BasicJsonType, typename T, ... void from_json(const BasicJsonType j, std::optionalT opt) { if (j.is_null()) { opt std::nullopt; } else { opt.emplace(j.template getT()); } } #endif // JSON_HAS_CPP_17同样地detail/conversions/to_json.hpp 与 detail/meta/type_traits.hpp 中也大量存在JSON_HAS_CPP_17条件分支用于判别std::optional、std::string_view等类型的特化路径。C20 相关concepts、三路比较与std::swap特化detail/input/input_adapters.hpp 中当__cpp_lib_concepts与JSON_HAS_CPP_20同时满足时会走基于 concepts 的输入适配器约束include/nlohmann/json.hpp 第 5368–5380 行注释明确指出“C20 禁止在std命名空间内对函数进行特化”因此在#ifndef JSON_HAS_CPP_20保护下才提供std::swap的旧式特化而 C20 下改用相关的三路比较实现参见 json_has_three_way_comparison 宏。C26 相关弃用特性规避在 detail/output/binary_writer.hpp 第 1891–1896 行JSON_HAS_CPP_26被用来在 C26 下规避对std::is_trivial已弃用的依赖改用std::is_trivially_copyable与std::is_trivially_default_constructible完成字符类型的static_assert校验#ifdef JSON_HAS_CPP_26 static_assert(std::is_trivially_copyableCharType::value, CharType must be trivially copyable); static_assert(std::is_trivially_default_constructibleCharType::value, CharType must be trivially default constructible); #else static_assert(std::is_trivialCharType::value, CharType must be trivial); #endif由此可见从 C11 基线到 C26 前沿这些宏贯穿了解析、序列化、类型转换与标准库适配的几乎所有层面对它们进行手动覆盖本质上是在告诉整个库“请按我声明的标准版本编译”。何时需要手动覆盖以及如何正确覆盖库文档明确给出的动机是某些编译器只实现了标准的局部内容会被自动检测逻辑误判此时需要由开发者显式声明真实的编译标准。典型用法是在包含头文件之前定义相应宏示例以 C14 为例#define JSON_HAS_CPP_14 1 #include nlohmann/json.hpp // ...需要注意两点关键语义一旦手动定义任意一个宏自动检测会被整体跳过见 macro_scope.hpp 第 35 行最外层的#if !defined(...)保护库不再补全其余标准的宏因此手动覆盖时必须自行定义所有适用层级的宏包括JSON_HAS_CPP_11。例如按 C17 编译却需强制指定时应当同时给出#define JSON_HAS_CPP_11 1 #define JSON_HAS_CPP_14 1 #define JSON_HAS_CPP_17 1 #include nlohmann/json.hpp这与自动检测“逐档向下、直到 C11 全部点亮”的行为保持一致。如果只定义JSON_HAS_CPP_17其余低层级宏缺失可能导致使用这些宏的#ifndef/#ifdef分支例如需要“非 C17 回退路径”的代码进入与真实编译标准不符的状态。此外这些宏与库中另一组“特性开关”宏协同工作例如JSON_HAS_FILESYSTEM、JSON_HAS_STATIC_RTTI、JSON_HAS_STD_FORMAT、JSON_HAS_RANGES、JSON_HAS_THREE_WAY_COMPARISON对应文档见 api/macros 目录。JSON_HAS_CPP_*定义的是“正在使用哪个语言标准”后者判断的是“当前标准库是否可用某项具体特性”两者在#if条件中常组合出现。重要副作用所有宏在库外被取消定义这六个宏与库中绝大部分内部宏一样作用域被严格限定在头文件内部。在json.hpp的收尾阶段会引入 include/nlohmann/detail/macro_unscope.hpp它执行一系列#undef清理其中就包括#undef JSON_HAS_CPP_11 #undef JSON_HAS_CPP_14 #undef JSON_HAS_CPP_17 #undef JSON_HAS_CPP_20 #undef JSON_HAS_CPP_23 #undef JSON_HAS_CPP_26因此这些宏并不会“泄漏”到你自己的翻译单元中影响后续代码。唯一的例外是当定义JSON_TEST_KEEP_MACROS时库测试框架自用清理动作会被跳过。一个实用的推论是若你在包含nlohmann/json.hpp之后再去#ifdef JSON_HAS_CPP_17宏已经不存在若希望在包含之前强制指定标准则宏必须定义在 include 之前且对当前编译单元持续生效到头文件末尾。版本历史依据官方 API 文档docs/mkdocs/docs/api/macros/json_has_cpp_11.md记录的版本演变3.10.5新增JSON_HAS_CPP_11、JSON_HAS_CPP_14、JSON_HAS_CPP_17、JSON_HAS_CPP_203.12.0新增JSON_HAS_CPP_233.13.0新增JSON_HAS_CPP_26。在当前仓库中macro_scope.hpp的自动检测已包含 202302L的 C26 阈值分支且binary_writer.hpp等文件已实际引用JSON_HAS_CPP_26说明检测与使用逻辑在代码中已完整落地。实践建议小结绝大多数场景无需干预GCC、Clang 与新版 MSVC 的__cplusplus/_MSVC_LANG均已准确反映实际标准自动检测足够可靠仅在编译器特性支持不完整、被误判时手动覆盖且覆盖值必须与编译命令中的-stdc17、/std:c17等真实标准保持一致覆盖要成套给出从JSON_HAS_CPP_11到目标标准逐一定义避免半套定义造成条件分支错乱定义位置务必在首次#include nlohmann/json.hpp之前因为宏在头文件处理结束后即被#undef清理。理解这六个宏就等于拿到了 nlohmann/json 条件编译体系的主钥匙——它决定了std::string_view解析、std::optional转换、concepts 适配乃至 C26 弃用特性规避等能力在你当前编译标准下是否被激活。【免费下载链接】jsonJSON for Modern C项目地址: https://gitcode.com/GitHub_Trending/js/json创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表