From 1419aeff60749066e0357fde8765ef0336021c7e Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Mon, 28 Sep 2026 21:49:37 +0200 Subject: [PATCH] Move the user-defined string literals to Following the review in #5294, the literals now live in their own header instead of being removed entirely: includes it at the end unless JSON_NO_AUTOMATIC_UDLS (renamed from JSON_NO_UDLS) is defined, so a project can opt out globally and include the header only where the literals are used. The header only uses public and standard macros, because the library's internal macros are undefined at the end of json.hpp and the amalgamation inlines macro_scope.hpp only once. For the same reason, the library no longer defines and undefines JSON_USE_GLOBAL_UDLS, so a user's definition is still visible to the header. The single-header copy is identical to the multi-header one, as it only includes . The module always exports the literals. Signed-off-by: Niels Lohmann --- .github/workflows/check_amalgamation.yml | 1 + BUILD.bazel | 1 + Makefile | 21 ++- cmake/ci.cmake | 5 +- docs/mkdocs/docs/api/macros/index.md | 2 +- .../docs/api/macros/json_no_automatic_udls.md | 68 ++++++++ docs/mkdocs/docs/api/macros/json_no_udls.md | 61 ------- .../docs/api/macros/json_use_global_udls.md | 7 +- docs/mkdocs/docs/api/operator_literal_json.md | 8 +- .../docs/api/operator_literal_json_pointer.md | 8 +- docs/mkdocs/docs/features/macros.md | 17 +- docs/mkdocs/docs/features/modules.md | 4 +- docs/mkdocs/docs/integration/index.md | 5 +- docs/mkdocs/mkdocs.yml | 2 +- include/nlohmann/detail/macro_scope.hpp | 4 - include/nlohmann/detail/macro_unscope.hpp | 1 - include/nlohmann/json.hpp | 70 +------- include/nlohmann/json_literals.hpp | 83 +++++++++ meson.build | 1 + single_include/nlohmann/json.hpp | 160 ++++++++++-------- single_include/nlohmann/json_literals.hpp | 83 +++++++++ src/modules/json.cppm | 3 +- ...no_udls.cpp => unit-no_automatic_udls.cpp} | 36 +++- 23 files changed, 418 insertions(+), 233 deletions(-) create mode 100644 docs/mkdocs/docs/api/macros/json_no_automatic_udls.md delete mode 100644 docs/mkdocs/docs/api/macros/json_no_udls.md create mode 100644 include/nlohmann/json_literals.hpp create mode 100644 single_include/nlohmann/json_literals.hpp rename tests/src/{unit-no_udls.cpp => unit-no_automatic_udls.cpp} (66%) diff --git a/.github/workflows/check_amalgamation.yml b/.github/workflows/check_amalgamation.yml index 670269cbb..35f3a57f7 100644 --- a/.github/workflows/check_amalgamation.yml +++ b/.github/workflows/check_amalgamation.yml @@ -67,6 +67,7 @@ jobs: python3 $TOOL_DIR/amalgamate.py -c $TOOL_DIR/config_json.json -s . python3 $TOOL_DIR/amalgamate.py -c $TOOL_DIR/config_json_fwd.json -s . + cp include/nlohmann/json_literals.hpp $INCLUDE_DIR/json_literals.hpp # the header list of the Bazel "json" target must match the files in include/ cmake -P cmake/scripts/gen_bazel_build_file.cmake diff --git a/BUILD.bazel b/BUILD.bazel index db59095cd..5f2bea555 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -65,6 +65,7 @@ cc_library( "include/nlohmann/detail/value_t.hpp", "include/nlohmann/json.hpp", "include/nlohmann/json_fwd.hpp", + "include/nlohmann/json_literals.hpp", "include/nlohmann/ordered_map.hpp", "include/nlohmann/thirdparty/hedley/hedley.hpp", "include/nlohmann/thirdparty/hedley/hedley_undef.hpp", diff --git a/Makefile b/Makefile index 196f87243..ccea759af 100644 --- a/Makefile +++ b/Makefile @@ -21,6 +21,8 @@ TESTS_SRCS=$(shell find tests -type f \( -name '*.hpp' -o -name '*.cpp' -o -name # the single headers (amalgamated from the source files) AMALGAMATED_FILE=single_include/nlohmann/json.hpp AMALGAMATED_FWD_FILE=single_include/nlohmann/json_fwd.hpp +# json_literals.hpp only includes , so it is copied verbatim +AMALGAMATED_LITERALS_FILE=single_include/nlohmann/json_literals.hpp ########################################################################## @@ -29,7 +31,7 @@ AMALGAMATED_FWD_FILE=single_include/nlohmann/json_fwd.hpp # main target all: - @echo "amalgamate - amalgamate files single_include/nlohmann/json{,_fwd}.hpp from the include/nlohmann sources" + @echo "amalgamate - amalgamate files single_include/nlohmann/json{,_fwd,_literals}.hpp from the include/nlohmann sources" @echo "BUILD.bazel - regenerate the Bazel BUILD file from the include/nlohmann sources" @echo "ChangeLog.md - generate ChangeLog file" @echo "check-amalgamation - check whether sources have been amalgamated and BUILD.bazel is up to date" @@ -154,14 +156,14 @@ install_astyle: # call the Artistic Style pretty printer on all source files pretty: install_astyle - $(ASTYLE) --project=tools/astyle/.astylerc $(SRCS) $(TESTS_SRCS) $(AMALGAMATED_FILE) $(AMALGAMATED_FWD_FILE) docs/mkdocs/docs/examples/*.cpp + $(ASTYLE) --project=tools/astyle/.astylerc $(SRCS) $(TESTS_SRCS) $(AMALGAMATED_FILE) $(AMALGAMATED_FWD_FILE) $(AMALGAMATED_LITERALS_FILE) docs/mkdocs/docs/examples/*.cpp # call the Clang-Format on all source files pretty_format: for FILE in $(SRCS) $(TESTS_SRCS) $(AMALGAMATED_FILE) docs/mkdocs/docs/examples/*.cpp; do echo $$FILE; clang-format -i $$FILE; done # create single header files and pretty print -amalgamate: $(AMALGAMATED_FILE) $(AMALGAMATED_FWD_FILE) +amalgamate: $(AMALGAMATED_FILE) $(AMALGAMATED_FWD_FILE) $(AMALGAMATED_LITERALS_FILE) $(MAKE) pretty # call the amalgamation tool for json.hpp @@ -172,16 +174,23 @@ $(AMALGAMATED_FILE): $(SRCS) $(AMALGAMATED_FWD_FILE): $(SRCS) tools/amalgamate/amalgamate.py -c tools/amalgamate/config_json_fwd.json -s . --verbose=yes +# copy json_literals.hpp +$(AMALGAMATED_LITERALS_FILE): include/nlohmann/json_literals.hpp + cp include/nlohmann/json_literals.hpp $(AMALGAMATED_LITERALS_FILE) + # check if file single_include/nlohmann/json.hpp has been amalgamated from the nlohmann sources # Note: this target is called by Travis check-amalgamation: @mv $(AMALGAMATED_FILE) $(AMALGAMATED_FILE)~ @mv $(AMALGAMATED_FWD_FILE) $(AMALGAMATED_FWD_FILE)~ + @mv $(AMALGAMATED_LITERALS_FILE) $(AMALGAMATED_LITERALS_FILE)~ @$(MAKE) amalgamate @diff $(AMALGAMATED_FILE) $(AMALGAMATED_FILE)~ || (echo "===================================================================\n Amalgamation required! Please read the contribution guidelines\n in file .github/CONTRIBUTING.md.\n===================================================================" ; mv $(AMALGAMATED_FILE)~ $(AMALGAMATED_FILE) ; false) @diff $(AMALGAMATED_FWD_FILE) $(AMALGAMATED_FWD_FILE)~ || (echo "===================================================================\n Amalgamation required! Please read the contribution guidelines\n in file .github/CONTRIBUTING.md.\n===================================================================" ; mv $(AMALGAMATED_FWD_FILE)~ $(AMALGAMATED_FWD_FILE) ; false) + @diff $(AMALGAMATED_LITERALS_FILE) $(AMALGAMATED_LITERALS_FILE)~ || (echo "===================================================================\n Amalgamation required! Please read the contribution guidelines\n in file .github/CONTRIBUTING.md.\n===================================================================" ; mv $(AMALGAMATED_LITERALS_FILE)~ $(AMALGAMATED_LITERALS_FILE) ; false) @mv $(AMALGAMATED_FILE)~ $(AMALGAMATED_FILE) @mv $(AMALGAMATED_FWD_FILE)~ $(AMALGAMATED_FWD_FILE) + @mv $(AMALGAMATED_LITERALS_FILE)~ $(AMALGAMATED_LITERALS_FILE) @mv BUILD.bazel BUILD.bazel~ @$(MAKE) BUILD.bazel @diff BUILD.bazel BUILD.bazel~ || (echo "===================================================================\n BUILD.bazel is out of date! Please run 'make BUILD.bazel'.\n===================================================================" ; mv BUILD.bazel~ BUILD.bazel ; false) @@ -222,7 +231,7 @@ json.tar.xz: # We use `-X` to make the resulting ZIP file reproducible, see # . include.zip: BUILD.bazel - zip -9 --recurse-paths -X include.zip $(SRCS) $(AMALGAMATED_FILE) $(AMALGAMATED_FWD_FILE) BUILD.bazel MODULE.bazel meson.build LICENSE.MIT + zip -9 --recurse-paths -X include.zip $(SRCS) $(AMALGAMATED_FILE) $(AMALGAMATED_FWD_FILE) $(AMALGAMATED_LITERALS_FILE) BUILD.bazel MODULE.bazel meson.build LICENSE.MIT # Create the files for a release and add signatures and hashes. release: include.zip json.tar.xz @@ -231,10 +240,12 @@ release: include.zip json.tar.xz gpg --armor --detach-sig include.zip gpg --armor --detach-sig $(AMALGAMATED_FILE) gpg --armor --detach-sig $(AMALGAMATED_FWD_FILE) + gpg --armor --detach-sig $(AMALGAMATED_LITERALS_FILE) gpg --armor --detach-sig json.tar.xz cp $(AMALGAMATED_FILE) release_files cp $(AMALGAMATED_FWD_FILE) release_files - mv $(AMALGAMATED_FILE).asc $(AMALGAMATED_FWD_FILE).asc json.tar.xz json.tar.xz.asc include.zip include.zip.asc release_files + cp $(AMALGAMATED_LITERALS_FILE) release_files + mv $(AMALGAMATED_FILE).asc $(AMALGAMATED_FWD_FILE).asc $(AMALGAMATED_LITERALS_FILE).asc json.tar.xz json.tar.xz.asc include.zip include.zip.asc release_files cd release_files ; shasum -a 256 json.hpp include.zip json.tar.xz > hashes.txt diff --git a/cmake/ci.cmake b/cmake/ci.cmake index f7695c36e..a001a05ae 100644 --- a/cmake/ci.cmake +++ b/cmake/ci.cmake @@ -373,9 +373,10 @@ file(GLOB_RECURSE INDENT_FILES set(include_dir ${PROJECT_SOURCE_DIR}/single_include/nlohmann) set(tool_dir ${PROJECT_SOURCE_DIR}/tools/amalgamate) add_custom_target(ci_test_amalgamation - COMMAND rm -fr ${include_dir}/json.hpp~ ${include_dir}/json_fwd.hpp~ + COMMAND rm -fr ${include_dir}/json.hpp~ ${include_dir}/json_fwd.hpp~ ${include_dir}/json_literals.hpp~ COMMAND cp ${include_dir}/json.hpp ${include_dir}/json.hpp~ COMMAND cp ${include_dir}/json_fwd.hpp ${include_dir}/json_fwd.hpp~ + COMMAND cp ${include_dir}/json_literals.hpp ${include_dir}/json_literals.hpp~ COMMAND ${Python3_EXECUTABLE} -mvenv venv_astyle COMMAND venv_astyle/bin/pip3 --quiet install -r ${CMAKE_SOURCE_DIR}/tools/astyle/requirements.txt @@ -383,10 +384,12 @@ add_custom_target(ci_test_amalgamation COMMAND ${Python3_EXECUTABLE} ${tool_dir}/amalgamate.py -c ${tool_dir}/config_json.json -s . COMMAND ${Python3_EXECUTABLE} ${tool_dir}/amalgamate.py -c ${tool_dir}/config_json_fwd.json -s . + COMMAND cp ${PROJECT_SOURCE_DIR}/include/nlohmann/json_literals.hpp ${include_dir}/json_literals.hpp COMMAND venv_astyle/bin/astyle --project=tools/astyle/.astylerc --suffix=none ${include_dir}/json.hpp ${include_dir}/json_fwd.hpp COMMAND diff ${include_dir}/json.hpp~ ${include_dir}/json.hpp COMMAND diff ${include_dir}/json_fwd.hpp~ ${include_dir}/json_fwd.hpp + COMMAND diff ${include_dir}/json_literals.hpp~ ${include_dir}/json_literals.hpp COMMAND venv_astyle/bin/astyle --project=tools/astyle/.astylerc --suffix=orig ${INDENT_FILES} COMMAND for FILE in `find . -name '*.orig'`\; do false \; done diff --git a/docs/mkdocs/docs/api/macros/index.md b/docs/mkdocs/docs/api/macros/index.md index a59af1eaa..9d2636eb2 100644 --- a/docs/mkdocs/docs/api/macros/index.md +++ b/docs/mkdocs/docs/api/macros/index.md @@ -28,9 +28,9 @@ header. See also the [macro overview page](../../features/macros.md). - [**JSON_HAS_RANGES**](json_has_ranges.md) - control `std::ranges` support - [**JSON_HAS_STD_FORMAT**](json_has_std_format.md) - control `std::format`/`std::formatter` support - [**JSON_HAS_THREE_WAY_COMPARISON**](json_has_three_way_comparison.md) - control 3-way comparison support +- [**JSON_NO_AUTOMATIC_UDLS**](json_no_automatic_udls.md) - do not include the user-defined string literals (UDLs) automatically - [**JSON_NO_IO**](json_no_io.md) - switch off functions relying on certain C++ I/O headers - [**JSON_NO_THREAD_LOCAL**](json_no_thread_local.md) - switch off the use of `thread_local` storage -- [**JSON_NO_UDLS**](json_no_udls.md) - leave out the user-defined string literals (UDLs) to reduce compile time - [**JSON_SKIP_UNSUPPORTED_COMPILER_CHECK**](json_skip_unsupported_compiler_check.md) - do not warn about unsupported compilers - [**JSON_USE_GLOBAL_UDLS**](json_use_global_udls.md) - place user-defined string literals (UDLs) into the global namespace - [**JSON_USE_SIMDUTF**](json_use_simdutf.md) - use the simdutf library to accelerate UTF-8 validation diff --git a/docs/mkdocs/docs/api/macros/json_no_automatic_udls.md b/docs/mkdocs/docs/api/macros/json_no_automatic_udls.md new file mode 100644 index 000000000..acb6a356e --- /dev/null +++ b/docs/mkdocs/docs/api/macros/json_no_automatic_udls.md @@ -0,0 +1,68 @@ +# JSON_NO_AUTOMATIC_UDLS + +```cpp +#define JSON_NO_AUTOMATIC_UDLS +``` + +When defined, `` does not include ``, so the user-defined string +literals [`operator""_json`](../operator_literal_json.md) and +[`operator""_json_pointer`](../operator_literal_json_pointer.md) are not declared. Include +`` in the files that use them. + +The literals are ordinary inline functions whose bodies call the parser, so every translation unit that includes them +instantiates the parser — even if it never parses anything itself. Defining `JSON_NO_AUTOMATIC_UDLS` for a whole project +avoids this cost in translation units that do not parse (e.g., ones that only define types and conversions or pass +`json` values around) and reduces their compile time. + +## Default definition + +By default, `#!cpp JSON_NO_AUTOMATIC_UDLS` is not defined, and `` includes +``. + +```cpp +#undef JSON_NO_AUTOMATIC_UDLS +``` + +## Notes + +!!! info "Header ``" + + The header includes `` itself and places the literals according to + [`JSON_USE_GLOBAL_UDLS`](json_use_global_udls.md). It is part of the multi-header sources (`include/nlohmann`) + and of the single-header sources (`single_include/nlohmann`), next to `json.hpp`. + +!!! info "C++ modules" + + The `nlohmann.json` [module](../../features/modules.md) always exports the literals, regardless of this macro. + +## Examples + +??? example + + The code below includes the library without the literals and adds them in a single translation unit. + + ```cpp + // compiled with -DJSON_NO_AUTOMATIC_UDLS for the whole project + #include + + // this file uses the literals, so it includes them explicitly + #include + + int main() + { + auto j = R"({"foo": 42})"_json; + return j.at("/foo"_json_pointer) == 42 ? 0 : 1; + } + ``` + + Without the include of ``, the code would fail to compile. + +## See also + +- [`operator""_json`](../operator_literal_json.md) +- [`operator""_json_pointer`](../operator_literal_json_pointer.md) +- [`JSON_USE_GLOBAL_UDLS`](json_use_global_udls.md) - place user-defined string literals (UDLs) into the global namespace + +## Version history + +- Added in version 3.13.0. diff --git a/docs/mkdocs/docs/api/macros/json_no_udls.md b/docs/mkdocs/docs/api/macros/json_no_udls.md deleted file mode 100644 index 7e52d302f..000000000 --- a/docs/mkdocs/docs/api/macros/json_no_udls.md +++ /dev/null @@ -1,61 +0,0 @@ -# JSON_NO_UDLS - -```cpp -#define JSON_NO_UDLS -``` - -When defined, the user-defined string literals [`operator""_json`](../operator_literal_json.md) and -[`operator""_json_pointer`](../operator_literal_json_pointer.md) are not defined, neither in the namespace -`nlohmann::literals::json_literals` nor in the global namespace (regardless of -[`JSON_USE_GLOBAL_UDLS`](json_use_global_udls.md)). - -The literals are ordinary inline functions whose bodies call the parser, so every translation unit that includes the -library instantiates the parser — even if it never parses anything itself. Defining `JSON_NO_UDLS` avoids this and -reduces the compile time of such translation units (e.g., ones that only define types and conversions or pass `json` -values around). Everything else in the library is unaffected; use [`parse`](../basic_json/parse.md) and the -[`json_pointer`](../json_pointer/json_pointer.md) constructor instead of the literals. - -## Default definition - -By default, `#!cpp JSON_NO_UDLS` is not defined. - -```cpp -#undef JSON_NO_UDLS -``` - -## Notes - -!!! info "Per translation unit" - - The macro only removes declarations, so it can be defined for some translation units and not for others. Code that - uses `_json` or `_json_pointer` fails to compile when `JSON_NO_UDLS` is defined. - -## Examples - -??? example - - The code below leaves out the user-defined string literals and uses `parse` and the `json_pointer` constructor - instead. - - ```cpp - #define JSON_NO_UDLS 1 - #include - - int main() - { - // auto j = R"({"foo": 42})"_json; // This line would fail to compile - auto j = nlohmann::json::parse(R"({"foo": 42})"); - auto p = nlohmann::json::json_pointer("/foo"); - return j.at(p) == 42 ? 0 : 1; - } - ``` - -## See also - -- [`operator""_json`](../operator_literal_json.md) -- [`operator""_json_pointer`](../operator_literal_json_pointer.md) -- [`JSON_USE_GLOBAL_UDLS`](json_use_global_udls.md) - place user-defined string literals (UDLs) into the global namespace - -## Version history - -- Added in version 3.13.0. diff --git a/docs/mkdocs/docs/api/macros/json_use_global_udls.md b/docs/mkdocs/docs/api/macros/json_use_global_udls.md index f7ba822e1..0b055640e 100644 --- a/docs/mkdocs/docs/api/macros/json_use_global_udls.md +++ b/docs/mkdocs/docs/api/macros/json_use_global_udls.md @@ -15,7 +15,7 @@ The default value is `1`. #define JSON_USE_GLOBAL_UDLS 1 ``` -When the macro is not defined, the library will define it to its default value. +When the macro is not defined, the library behaves as if it were defined to its default value. ## Notes @@ -34,7 +34,8 @@ When the macro is not defined, the library will define it to its default value. !!! info "Leaving out the literals" - If [`JSON_NO_UDLS`](json_no_udls.md) is defined, the literals are not defined at all and this macro has no effect. + If [`JSON_NO_AUTOMATIC_UDLS`](json_no_automatic_udls.md) is defined, the literals are only declared where + `` is included; this macro then applies to that header. ## Examples @@ -96,7 +97,7 @@ When the macro is not defined, the library will define it to its default value. - [`operator""_json`](../operator_literal_json.md) - [`operator""_json_pointer`](../operator_literal_json_pointer.md) -- [`JSON_NO_UDLS`](json_no_udls.md) - leave out the user-defined string literals entirely +- [`JSON_NO_AUTOMATIC_UDLS`](json_no_automatic_udls.md) - do not include the user-defined string literals automatically - [:simple-cmake: JSON_GlobalUDLs](../../integration/cmake.md#json_globaludls) - CMake option to control the macro ## Version history diff --git a/docs/mkdocs/docs/api/operator_literal_json.md b/docs/mkdocs/docs/api/operator_literal_json.md index 15a5a606f..a909d8165 100644 --- a/docs/mkdocs/docs/api/operator_literal_json.md +++ b/docs/mkdocs/docs/api/operator_literal_json.md @@ -18,8 +18,9 @@ using namespace nlohmann; ``` This is suggested to ease migration to the next major version release of the library. See -[`JSON_USE_GLOBAL_UDLS`](macros/json_use_global_udls.md#notes) for details. The operator is not defined if -[`JSON_NO_UDLS`](macros/json_no_udls.md) is defined. +[`JSON_USE_GLOBAL_UDLS`](macros/json_use_global_udls.md#notes) for details. The operator is declared in header +``, which `` includes unless +[`JSON_NO_AUTOMATIC_UDLS`](macros/json_no_automatic_udls.md) is defined. ## Parameters @@ -60,7 +61,8 @@ Linear. ## See also - [Creating JSON values](../features/creating_values.md) - the article on creating JSON values -- [JSON_NO_UDLS](macros/json_no_udls.md) - leave out the user-defined string literals +- [JSON_NO_AUTOMATIC_UDLS](macros/json_no_automatic_udls.md) - do not include the user-defined string literals + automatically ## Version history diff --git a/docs/mkdocs/docs/api/operator_literal_json_pointer.md b/docs/mkdocs/docs/api/operator_literal_json_pointer.md index 5817963a4..0494439aa 100644 --- a/docs/mkdocs/docs/api/operator_literal_json_pointer.md +++ b/docs/mkdocs/docs/api/operator_literal_json_pointer.md @@ -17,8 +17,9 @@ using namespace nlohmann::literals::json_literals; using namespace nlohmann; ``` This is suggested to ease migration to the next major version release of the library. See -[`JSON_USE_GLOBAL_UDLS`](macros/json_use_global_udls.md#notes) for details. The operator is not defined if -[`JSON_NO_UDLS`](macros/json_no_udls.md) is defined. +[`JSON_USE_GLOBAL_UDLS`](macros/json_use_global_udls.md#notes) for details. The operator is declared in header +``, which `` includes unless +[`JSON_NO_AUTOMATIC_UDLS`](macros/json_no_automatic_udls.md) is defined. ## Parameters @@ -59,7 +60,8 @@ Linear. ## See also - [json_pointer](json_pointer/index.md) - type to represent JSON Pointers -- [JSON_NO_UDLS](macros/json_no_udls.md) - leave out the user-defined string literals +- [JSON_NO_AUTOMATIC_UDLS](macros/json_no_automatic_udls.md) - do not include the user-defined string literals + automatically ## Version history diff --git a/docs/mkdocs/docs/features/macros.md b/docs/mkdocs/docs/features/macros.md index 9a612fd07..e4a628c3e 100644 --- a/docs/mkdocs/docs/features/macros.md +++ b/docs/mkdocs/docs/features/macros.md @@ -83,6 +83,15 @@ When defined, default parse and serialize functions for enums are excluded and h See [full documentation of `JSON_DISABLE_ENUM_SERIALIZATION`](../api/macros/json_disable_enum_serialization.md). +## `JSON_NO_AUTOMATIC_UDLS` + +When defined, `` does not include `` with the user-defined string literals +`operator""_json` and `operator""_json_pointer`. This reduces the compile time of translation units that do not use +them, because the literals instantiate the parser in every translation unit that includes them. Include +`` where the literals are needed. + +See [full documentation of `JSON_NO_AUTOMATIC_UDLS`](../api/macros/json_no_automatic_udls.md). + ## `JSON_NO_IO` When defined, headers ``, ``, ``, ``, and `` are not included and parse functions @@ -99,14 +108,6 @@ same values and the same comparisons. See [full documentation of `JSON_NO_THREAD_LOCAL`](../api/macros/json_no_thread_local.md). -## `JSON_NO_UDLS` - -When defined, the user-defined string literals `operator""_json` and `operator""_json_pointer` are left out entirely. This -reduces the compile time of translation units that do not use them, because the literals would otherwise instantiate -the parser in every translation unit that includes the library. - -See [full documentation of `JSON_NO_UDLS`](../api/macros/json_no_udls.md). - ## `JSON_PRECISE_STREAM_POSITION` When defined to `1`, [`operator>>`](../api/operator_gtgt.md) and non-strict diff --git a/docs/mkdocs/docs/features/modules.md b/docs/mkdocs/docs/features/modules.md index 72d4ca6d5..32e9ba7fd 100644 --- a/docs/mkdocs/docs/features/modules.md +++ b/docs/mkdocs/docs/features/modules.md @@ -40,8 +40,8 @@ Only the following symbols are exported from `nlohmann.json`: - `nlohmann::literals::json_literals::operator""_json` - `nlohmann::literals::json_literals::operator""_json_pointer` -The two user-defined string literals are not exported if [`JSON_NO_UDLS`](../api/macros/json_no_udls.md) is defined -when building the module. +The module always exports the two user-defined string literals, even if +[`JSON_NO_AUTOMATIC_UDLS`](../api/macros/json_no_automatic_udls.md) is defined when building it. Additionally, the following `nlohmann::detail` symbols are exported, solely to work around an MSVC compilation issue ([#3970](https://github.com/nlohmann/json/issues/3970)). They are implementation details, not part of the public API, diff --git a/docs/mkdocs/docs/integration/index.md b/docs/mkdocs/docs/integration/index.md index 2bbaa8604..99bf088b6 100644 --- a/docs/mkdocs/docs/integration/index.md +++ b/docs/mkdocs/docs/integration/index.md @@ -15,4 +15,7 @@ Clang). You can further use file [`single_include/nlohmann/json_fwd.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json_fwd.hpp) -for forward declarations. +for forward declarations, and file +[`single_include/nlohmann/json_literals.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json_literals.hpp) +for the user-defined string literals if you define +[`JSON_NO_AUTOMATIC_UDLS`](../api/macros/json_no_automatic_udls.md). diff --git a/docs/mkdocs/mkdocs.yml b/docs/mkdocs/mkdocs.yml index 65111c8ca..21fad832a 100644 --- a/docs/mkdocs/mkdocs.yml +++ b/docs/mkdocs/mkdocs.yml @@ -293,10 +293,10 @@ nav: - 'JSON_HAS_STATIC_RTTI': api/macros/json_has_static_rtti.md - 'JSON_HAS_STD_FORMAT': api/macros/json_has_std_format.md - 'JSON_HAS_THREE_WAY_COMPARISON': api/macros/json_has_three_way_comparison.md + - 'JSON_NO_AUTOMATIC_UDLS': api/macros/json_no_automatic_udls.md - 'JSON_NOEXCEPTION': api/macros/json_noexception.md - 'JSON_NO_IO': api/macros/json_no_io.md - 'JSON_NO_THREAD_LOCAL': api/macros/json_no_thread_local.md - - 'JSON_NO_UDLS': api/macros/json_no_udls.md - 'JSON_PRECISE_STREAM_POSITION': api/macros/json_precise_stream_position.md - 'JSON_SKIP_LIBRARY_VERSION_CHECK': api/macros/json_skip_library_version_check.md - 'JSON_SKIP_UNSUPPORTED_COMPILER_CHECK': api/macros/json_skip_unsupported_compiler_check.md diff --git a/include/nlohmann/detail/macro_scope.hpp b/include/nlohmann/detail/macro_scope.hpp index 3a4eb79f4..7c39afbeb 100644 --- a/include/nlohmann/detail/macro_scope.hpp +++ b/include/nlohmann/detail/macro_scope.hpp @@ -915,7 +915,3 @@ void templated_json_throw(ExceptionType exception) #ifndef JSON_DISABLE_ENUM_SERIALIZATION #define JSON_DISABLE_ENUM_SERIALIZATION 0 #endif - -#ifndef JSON_USE_GLOBAL_UDLS - #define JSON_USE_GLOBAL_UDLS 1 -#endif diff --git a/include/nlohmann/detail/macro_unscope.hpp b/include/nlohmann/detail/macro_unscope.hpp index a73951a22..d2675d3f1 100644 --- a/include/nlohmann/detail/macro_unscope.hpp +++ b/include/nlohmann/detail/macro_unscope.hpp @@ -25,7 +25,6 @@ #undef JSON_INLINE_VARIABLE #undef JSON_NO_UNIQUE_ADDRESS #undef JSON_DISABLE_ENUM_SERIALIZATION -#undef JSON_USE_GLOBAL_UDLS #ifndef JSON_TEST_KEEP_MACROS #undef JSON_CATCH diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index d7dcfa6e2..6f3ec5b40 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -6423,57 +6423,6 @@ std::string format_as(const NLOHMANN_BASIC_JSON_TPL& j) return j.dump(); } -#ifndef JSON_NO_UDLS -inline namespace literals -{ -inline namespace json_literals -{ - -/// @brief user-defined string literal for JSON values -/// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json/ -JSON_HEDLEY_NON_NULL(1) -#if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) - inline nlohmann::json operator""_json(const char* s, std::size_t n) -#else - // GCC 4.8 requires a space between "" and suffix - inline nlohmann::json operator"" _json(const char* s, std::size_t n) -#endif -{ - return nlohmann::json::parse(s, s + n); -} - -#if defined(__cpp_char8_t) -JSON_HEDLEY_NON_NULL(1) -inline nlohmann::json operator""_json(const char8_t* s, std::size_t n) -{ - return nlohmann::json::parse(reinterpret_cast(s), - reinterpret_cast(s) + n); -} -#endif - -/// @brief user-defined string literal for JSON pointer -/// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json_pointer/ -JSON_HEDLEY_NON_NULL(1) -#if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) - inline nlohmann::json::json_pointer operator""_json_pointer(const char* s, std::size_t n) -#else - // GCC 4.8 requires a space between "" and suffix - inline nlohmann::json::json_pointer operator"" _json_pointer(const char* s, std::size_t n) -#endif -{ - return nlohmann::json::json_pointer(std::string(s, n)); -} - -#if defined(__cpp_char8_t) -inline nlohmann::json::json_pointer operator""_json_pointer(const char8_t* s, std::size_t n) -{ - return nlohmann::json::json_pointer(std::string(reinterpret_cast(s), n)); -} -#endif - -} // namespace json_literals -} // namespace literals -#endif // JSON_NO_UDLS NLOHMANN_JSON_NAMESPACE_END /////////////////////// @@ -6608,17 +6557,6 @@ struct formatter // NOLINT(cert-dcl58-c } // namespace std -#if JSON_USE_GLOBAL_UDLS && !defined(JSON_NO_UDLS) - #if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) - using nlohmann::literals::json_literals::operator""_json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers) - using nlohmann::literals::json_literals::operator""_json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers) - #else - // GCC 4.8 requires a space between "" and suffix - using nlohmann::literals::json_literals::operator"" _json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers) - using nlohmann::literals::json_literals::operator"" _json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers) - #endif -#endif - #include // End of GCC diagnostic pragmas for C++ modules support @@ -6626,4 +6564,12 @@ struct formatter // NOLINT(cert-dcl58-c #pragma GCC diagnostic pop #endif +// The user-defined string literals are in a separate header, because their +// bodies instantiate the parser in every translation unit that includes them. +// Define JSON_NO_AUTOMATIC_UDLS to include only +// where needed. +#ifndef JSON_NO_AUTOMATIC_UDLS + #include +#endif + #endif // INCLUDE_NLOHMANN_JSON_HPP_ diff --git a/include/nlohmann/json_literals.hpp b/include/nlohmann/json_literals.hpp new file mode 100644 index 000000000..d62e0cf2e --- /dev/null +++ b/include/nlohmann/json_literals.hpp @@ -0,0 +1,83 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann +// SPDX-License-Identifier: MIT + +#ifndef INCLUDE_NLOHMANN_JSON_LITERALS_HPP_ +#define INCLUDE_NLOHMANN_JSON_LITERALS_HPP_ + +#include // size_t +#include // string + +#include + +// This header is included at the end of unless +// JSON_NO_AUTOMATIC_UDLS is defined, and can be included on its own after that. +// Either way, the library's internal macros are no longer defined here (and the +// amalgamation inlines macro_scope.hpp only once), so only standard and public +// macros may be used below. + +NLOHMANN_JSON_NAMESPACE_BEGIN +inline namespace literals +{ +inline namespace json_literals +{ + +/// @brief user-defined string literal for JSON values +/// @sa https://json.nlohmann.me/api/operator_literal_json/ +#if !defined(__GNUC__) || defined(__clang__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9) + inline nlohmann::json operator""_json(const char* s, std::size_t n) +#else + // GCC 4.8 requires a space between "" and suffix + inline nlohmann::json operator"" _json(const char* s, std::size_t n) +#endif +{ + return nlohmann::json::parse(s, s + n); +} + +#if defined(__cpp_char8_t) +inline nlohmann::json operator""_json(const char8_t* s, std::size_t n) +{ + return nlohmann::json::parse(reinterpret_cast(s), + reinterpret_cast(s) + n); +} +#endif + +/// @brief user-defined string literal for JSON pointer +/// @sa https://json.nlohmann.me/api/operator_literal_json_pointer/ +#if !defined(__GNUC__) || defined(__clang__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9) + inline nlohmann::json::json_pointer operator""_json_pointer(const char* s, std::size_t n) +#else + // GCC 4.8 requires a space between "" and suffix + inline nlohmann::json::json_pointer operator"" _json_pointer(const char* s, std::size_t n) +#endif +{ + return nlohmann::json::json_pointer(std::string(s, n)); +} + +#if defined(__cpp_char8_t) +inline nlohmann::json::json_pointer operator""_json_pointer(const char8_t* s, std::size_t n) +{ + return nlohmann::json::json_pointer(std::string(reinterpret_cast(s), n)); +} +#endif + +} // namespace json_literals +} // namespace literals +NLOHMANN_JSON_NAMESPACE_END + +#if !defined(JSON_USE_GLOBAL_UDLS) || JSON_USE_GLOBAL_UDLS + #if !defined(__GNUC__) || defined(__clang__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9) + using nlohmann::literals::json_literals::operator""_json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers) + using nlohmann::literals::json_literals::operator""_json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers) + #else + // GCC 4.8 requires a space between "" and suffix + using nlohmann::literals::json_literals::operator"" _json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers) + using nlohmann::literals::json_literals::operator"" _json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers) + #endif +#endif + +#endif // INCLUDE_NLOHMANN_JSON_LITERALS_HPP_ diff --git a/meson.build b/meson.build index a2d6e31a2..2800957ec 100644 --- a/meson.build +++ b/meson.build @@ -15,6 +15,7 @@ nlohmann_json_multiple_headers = declare_dependency( if not meson.is_subproject() install_headers('single_include/nlohmann/json.hpp', subdir: 'nlohmann') install_headers('single_include/nlohmann/json_fwd.hpp', subdir: 'nlohmann') +install_headers('single_include/nlohmann/json_literals.hpp', subdir: 'nlohmann') pkgc = import('pkgconfig') pkgc.generate(name: 'nlohmann_json', diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index e73583e17..14ae985f3 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -3327,10 +3327,6 @@ void templated_json_throw(ExceptionType exception) #define JSON_DISABLE_ENUM_SERIALIZATION 0 #endif -#ifndef JSON_USE_GLOBAL_UDLS - #define JSON_USE_GLOBAL_UDLS 1 -#endif - #if JSON_HAS_THREE_WAY_COMPARISON #include // partial_ordering #endif @@ -32504,57 +32500,6 @@ std::string format_as(const NLOHMANN_BASIC_JSON_TPL& j) return j.dump(); } -#ifndef JSON_NO_UDLS -inline namespace literals -{ -inline namespace json_literals -{ - -/// @brief user-defined string literal for JSON values -/// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json/ -JSON_HEDLEY_NON_NULL(1) -#if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) - inline nlohmann::json operator""_json(const char* s, std::size_t n) -#else - // GCC 4.8 requires a space between "" and suffix - inline nlohmann::json operator"" _json(const char* s, std::size_t n) -#endif -{ - return nlohmann::json::parse(s, s + n); -} - -#if defined(__cpp_char8_t) -JSON_HEDLEY_NON_NULL(1) -inline nlohmann::json operator""_json(const char8_t* s, std::size_t n) -{ - return nlohmann::json::parse(reinterpret_cast(s), - reinterpret_cast(s) + n); -} -#endif - -/// @brief user-defined string literal for JSON pointer -/// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json_pointer/ -JSON_HEDLEY_NON_NULL(1) -#if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) - inline nlohmann::json::json_pointer operator""_json_pointer(const char* s, std::size_t n) -#else - // GCC 4.8 requires a space between "" and suffix - inline nlohmann::json::json_pointer operator"" _json_pointer(const char* s, std::size_t n) -#endif -{ - return nlohmann::json::json_pointer(std::string(s, n)); -} - -#if defined(__cpp_char8_t) -inline nlohmann::json::json_pointer operator""_json_pointer(const char8_t* s, std::size_t n) -{ - return nlohmann::json::json_pointer(std::string(reinterpret_cast(s), n)); -} -#endif - -} // namespace json_literals -} // namespace literals -#endif // JSON_NO_UDLS NLOHMANN_JSON_NAMESPACE_END /////////////////////// @@ -32689,17 +32634,6 @@ struct formatter // NOLINT(cert-dcl58-c } // namespace std -#if JSON_USE_GLOBAL_UDLS && !defined(JSON_NO_UDLS) - #if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) - using nlohmann::literals::json_literals::operator""_json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers) - using nlohmann::literals::json_literals::operator""_json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers) - #else - // GCC 4.8 requires a space between "" and suffix - using nlohmann::literals::json_literals::operator"" _json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers) - using nlohmann::literals::json_literals::operator"" _json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers) - #endif -#endif - // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ @@ -32728,7 +32662,6 @@ struct formatter // NOLINT(cert-dcl58-c #undef JSON_INLINE_VARIABLE #undef JSON_NO_UNIQUE_ADDRESS #undef JSON_DISABLE_ENUM_SERIALIZATION -#undef JSON_USE_GLOBAL_UDLS #ifndef JSON_TEST_KEEP_MACROS #undef JSON_CATCH @@ -32921,4 +32854,97 @@ struct formatter // NOLINT(cert-dcl58-c #pragma GCC diagnostic pop #endif +// The user-defined string literals are in a separate header, because their +// bodies instantiate the parser in every translation unit that includes them. +// Define JSON_NO_AUTOMATIC_UDLS to include only +// where needed. +#ifndef JSON_NO_AUTOMATIC_UDLS +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann +// SPDX-License-Identifier: MIT + +#ifndef INCLUDE_NLOHMANN_JSON_LITERALS_HPP_ +#define INCLUDE_NLOHMANN_JSON_LITERALS_HPP_ + +#include // size_t +#include // string + +// #include + + +// This header is included at the end of unless +// JSON_NO_AUTOMATIC_UDLS is defined, and can be included on its own after that. +// Either way, the library's internal macros are no longer defined here (and the +// amalgamation inlines macro_scope.hpp only once), so only standard and public +// macros may be used below. + +NLOHMANN_JSON_NAMESPACE_BEGIN +inline namespace literals +{ +inline namespace json_literals +{ + +/// @brief user-defined string literal for JSON values +/// @sa https://json.nlohmann.me/api/operator_literal_json/ +#if !defined(__GNUC__) || defined(__clang__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9) + inline nlohmann::json operator""_json(const char* s, std::size_t n) +#else + // GCC 4.8 requires a space between "" and suffix + inline nlohmann::json operator"" _json(const char* s, std::size_t n) +#endif +{ + return nlohmann::json::parse(s, s + n); +} + +#if defined(__cpp_char8_t) +inline nlohmann::json operator""_json(const char8_t* s, std::size_t n) +{ + return nlohmann::json::parse(reinterpret_cast(s), + reinterpret_cast(s) + n); +} +#endif + +/// @brief user-defined string literal for JSON pointer +/// @sa https://json.nlohmann.me/api/operator_literal_json_pointer/ +#if !defined(__GNUC__) || defined(__clang__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9) + inline nlohmann::json::json_pointer operator""_json_pointer(const char* s, std::size_t n) +#else + // GCC 4.8 requires a space between "" and suffix + inline nlohmann::json::json_pointer operator"" _json_pointer(const char* s, std::size_t n) +#endif +{ + return nlohmann::json::json_pointer(std::string(s, n)); +} + +#if defined(__cpp_char8_t) +inline nlohmann::json::json_pointer operator""_json_pointer(const char8_t* s, std::size_t n) +{ + return nlohmann::json::json_pointer(std::string(reinterpret_cast(s), n)); +} +#endif + +} // namespace json_literals +} // namespace literals +NLOHMANN_JSON_NAMESPACE_END + +#if !defined(JSON_USE_GLOBAL_UDLS) || JSON_USE_GLOBAL_UDLS + #if !defined(__GNUC__) || defined(__clang__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9) + using nlohmann::literals::json_literals::operator""_json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers) + using nlohmann::literals::json_literals::operator""_json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers) + #else + // GCC 4.8 requires a space between "" and suffix + using nlohmann::literals::json_literals::operator"" _json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers) + using nlohmann::literals::json_literals::operator"" _json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers) + #endif +#endif + +#endif // INCLUDE_NLOHMANN_JSON_LITERALS_HPP_ + +#endif + #endif // INCLUDE_NLOHMANN_JSON_HPP_ diff --git a/single_include/nlohmann/json_literals.hpp b/single_include/nlohmann/json_literals.hpp new file mode 100644 index 000000000..d62e0cf2e --- /dev/null +++ b/single_include/nlohmann/json_literals.hpp @@ -0,0 +1,83 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann +// SPDX-License-Identifier: MIT + +#ifndef INCLUDE_NLOHMANN_JSON_LITERALS_HPP_ +#define INCLUDE_NLOHMANN_JSON_LITERALS_HPP_ + +#include // size_t +#include // string + +#include + +// This header is included at the end of unless +// JSON_NO_AUTOMATIC_UDLS is defined, and can be included on its own after that. +// Either way, the library's internal macros are no longer defined here (and the +// amalgamation inlines macro_scope.hpp only once), so only standard and public +// macros may be used below. + +NLOHMANN_JSON_NAMESPACE_BEGIN +inline namespace literals +{ +inline namespace json_literals +{ + +/// @brief user-defined string literal for JSON values +/// @sa https://json.nlohmann.me/api/operator_literal_json/ +#if !defined(__GNUC__) || defined(__clang__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9) + inline nlohmann::json operator""_json(const char* s, std::size_t n) +#else + // GCC 4.8 requires a space between "" and suffix + inline nlohmann::json operator"" _json(const char* s, std::size_t n) +#endif +{ + return nlohmann::json::parse(s, s + n); +} + +#if defined(__cpp_char8_t) +inline nlohmann::json operator""_json(const char8_t* s, std::size_t n) +{ + return nlohmann::json::parse(reinterpret_cast(s), + reinterpret_cast(s) + n); +} +#endif + +/// @brief user-defined string literal for JSON pointer +/// @sa https://json.nlohmann.me/api/operator_literal_json_pointer/ +#if !defined(__GNUC__) || defined(__clang__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9) + inline nlohmann::json::json_pointer operator""_json_pointer(const char* s, std::size_t n) +#else + // GCC 4.8 requires a space between "" and suffix + inline nlohmann::json::json_pointer operator"" _json_pointer(const char* s, std::size_t n) +#endif +{ + return nlohmann::json::json_pointer(std::string(s, n)); +} + +#if defined(__cpp_char8_t) +inline nlohmann::json::json_pointer operator""_json_pointer(const char8_t* s, std::size_t n) +{ + return nlohmann::json::json_pointer(std::string(reinterpret_cast(s), n)); +} +#endif + +} // namespace json_literals +} // namespace literals +NLOHMANN_JSON_NAMESPACE_END + +#if !defined(JSON_USE_GLOBAL_UDLS) || JSON_USE_GLOBAL_UDLS + #if !defined(__GNUC__) || defined(__clang__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9) + using nlohmann::literals::json_literals::operator""_json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers) + using nlohmann::literals::json_literals::operator""_json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers) + #else + // GCC 4.8 requires a space between "" and suffix + using nlohmann::literals::json_literals::operator"" _json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers) + using nlohmann::literals::json_literals::operator"" _json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers) + #endif +#endif + +#endif // INCLUDE_NLOHMANN_JSON_LITERALS_HPP_ diff --git a/src/modules/json.cppm b/src/modules/json.cppm index 480961f6b..a32b97603 100644 --- a/src/modules/json.cppm +++ b/src/modules/json.cppm @@ -18,6 +18,7 @@ module; // See: https://github.com/nlohmann/json/issues/5103 #include +#include export module nlohmann.json; @@ -32,7 +33,6 @@ using NLOHMANN_JSON_NAMESPACE::ordered_json; using NLOHMANN_JSON_NAMESPACE::ordered_map; using NLOHMANN_JSON_NAMESPACE::to_string; -#ifndef JSON_NO_UDLS inline namespace literals { inline namespace json_literals @@ -41,7 +41,6 @@ inline namespace json_literals using NLOHMANN_JSON_NAMESPACE::literals::json_literals::operator""_json_pointer; } // namespace json_literals } // namespace literals -#endif // Note: the following nlohmann::detail symbols must be exported due to // an MSVC bug failing to compile without these symbols visible (ticket #3970) diff --git a/tests/src/unit-no_udls.cpp b/tests/src/unit-no_automatic_udls.cpp similarity index 66% rename from tests/src/unit-no_udls.cpp rename to tests/src/unit-no_automatic_udls.cpp index bf5402b1c..001ed4251 100644 --- a/tests/src/unit-no_udls.cpp +++ b/tests/src/unit-no_automatic_udls.cpp @@ -6,10 +6,12 @@ // SPDX-FileCopyrightText: 2013-2026 Niels Lohmann // SPDX-License-Identifier: MIT -// This translation unit checks JSON_NO_UDLS, which leaves out the user-defined -// string literals operator""_json and operator""_json_pointer entirely (see -// #5294), while the rest of the library keeps working. -#define JSON_NO_UDLS 1 +// This translation unit checks JSON_NO_AUTOMATIC_UDLS, which keeps +// from including and thereby +// leaves out the user-defined string literals operator""_json and +// operator""_json_pointer (see #5294), and that including +// afterwards brings them back. +#define JSON_NO_AUTOMATIC_UDLS 1 #include "doctest_compatibility.h" @@ -23,7 +25,7 @@ using json = nlohmann::json; // argument-dependent lookup of a literal operator called by its function name // also searches the inline namespaces nlohmann::literals::json_literals. NLOHMANN_JSON_NAMESPACE_BEGIN -struct no_udls_probe +struct no_automatic_udls_probe { operator const char* () const // NOLINT(google-explicit-constructor,hicpp-explicit-conversions) { @@ -52,7 +54,7 @@ template using has_json_pointer_udl = nlohmann::detail::is_detected; } // namespace -TEST_CASE("JSON_NO_UDLS") +TEST_CASE("JSON_NO_AUTOMATIC_UDLS") { SECTION("literals are not declared") { @@ -61,8 +63,8 @@ TEST_CASE("JSON_NO_UDLS") CHECK_FALSE(has_json_pointer_udl::value); // nlohmann::literals::json_literals - CHECK_FALSE(has_json_udl::value); - CHECK_FALSE(has_json_pointer_udl::value); + CHECK_FALSE(has_json_udl::value); + CHECK_FALSE(has_json_pointer_udl::value); } SECTION("the rest of the library keeps working") @@ -75,3 +77,21 @@ TEST_CASE("JSON_NO_UDLS") CHECK(j.contains(ptr)); } } + +// the literals can still be added where they are needed +#include + +TEST_CASE("JSON_NO_AUTOMATIC_UDLS with ") +{ + SECTION("global namespace") + { + CHECK("[1,2]"_json == json({1, 2})); + CHECK("/a/0"_json_pointer == json::json_pointer("/a/0")); + } + + SECTION("nlohmann::literals::json_literals") + { + using namespace nlohmann::literals::json_literals; // NOLINT(google-build-using-namespace) + CHECK(R"({"a":[42]})"_json.at("/a/0"_json_pointer) == 42); + } +}