From 6fc0d501f37a6e58669a718527d295a847f7b942 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 30 Sep 2026 20:08:17 +0200 Subject: [PATCH] Move the user-defined string literals to and add JSON_NO_AUTOMATIC_UDLS (#5610) * Add JSON_NO_UDLS to leave out the user-defined string literals The bodies of operator""_json and operator""_json_pointer call the parser, so every translation unit including the library instantiates it, even if it never parses anything. Defining JSON_NO_UDLS leaves the literals out entirely, which saves 15-35% compile time for such translation units (#5294). Nothing changes if the macro is not defined. Signed-off-by: Niels Lohmann * Mention JSON_NO_UDLS in the list of exported module symbols Signed-off-by: Niels Lohmann * 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 * Fix CI: include cycle, GCC 4.8 literal operator spacing, and global UDLs off in the JSON_NO_AUTOMATIC_UDLS test - Suppress clang-tidy misc-header-include-cycle on the intentional mutual include of json.hpp and json_literals.hpp. - Use operator"" _json with a space for GCC 4.8 in the test's detection aliases, as the header does. - Only test the global literal operators when JSON_USE_GLOBAL_UDLS is on. Signed-off-by: Niels Lohmann * Declare the literal operators through a local macro The GCC 4.8 spacing condition was repeated for both operator definitions and the global using-declarations. NLOHMANN_JSON_LITERAL_OPERATOR(suffix) now selects operator""##suffix or operator"" suffix in one place and is undefined at the end of json_literals.hpp. Suggested by gregmarr in review. Signed-off-by: Niels Lohmann --------- 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 | 1 + .../docs/api/macros/json_no_automatic_udls.md | 68 ++++++++ .../docs/api/macros/json_use_global_udls.md | 8 +- docs/mkdocs/docs/api/operator_literal_json.md | 6 +- .../docs/api/operator_literal_json_pointer.md | 6 +- docs/mkdocs/docs/features/macros.md | 9 + docs/mkdocs/docs/features/modules.md | 3 + docs/mkdocs/docs/integration/index.md | 5 +- docs/mkdocs/mkdocs.yml | 1 + include/nlohmann/detail/macro_scope.hpp | 4 - include/nlohmann/detail/macro_unscope.hpp | 1 - include/nlohmann/json.hpp | 69 +------- include/nlohmann/json_literals.hpp | 78 +++++++++ meson.build | 1 + single_include/nlohmann/json.hpp | 154 ++++++++++-------- single_include/nlohmann/json_literals.hpp | 78 +++++++++ src/modules/json.cppm | 1 + tests/src/unit-no_automatic_udls.cpp | 108 ++++++++++++ 22 files changed, 489 insertions(+), 140 deletions(-) create mode 100644 docs/mkdocs/docs/api/macros/json_no_automatic_udls.md create mode 100644 include/nlohmann/json_literals.hpp create mode 100644 single_include/nlohmann/json_literals.hpp create mode 100644 tests/src/unit-no_automatic_udls.cpp 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 899f9196d..03f73fa92 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -67,6 +67,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 bf773b5c4..9d2636eb2 100644 --- a/docs/mkdocs/docs/api/macros/index.md +++ b/docs/mkdocs/docs/api/macros/index.md @@ -28,6 +28,7 @@ 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_SKIP_UNSUPPORTED_COMPILER_CHECK**](json_skip_unsupported_compiler_check.md) - do not warn about unsupported compilers 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_use_global_udls.md b/docs/mkdocs/docs/api/macros/json_use_global_udls.md index 3110d4662..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 @@ -32,6 +32,11 @@ When the macro is not defined, the library will define it to its default value. [`JSON_GlobalUDLs`](../../integration/cmake.md#json_globaludls) (`ON` by default) which defines `JSON_USE_GLOBAL_UDLS` accordingly. +!!! info "Leaving out the literals" + + 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 ??? example "Example 1: Default behavior" @@ -92,6 +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_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 babce5799..a909d8165 100644 --- a/docs/mkdocs/docs/api/operator_literal_json.md +++ b/docs/mkdocs/docs/api/operator_literal_json.md @@ -18,7 +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. +[`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,6 +61,8 @@ Linear. ## See also - [Creating JSON values](../features/creating_values.md) - the article on creating JSON values +- [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 e1b729467..0494439aa 100644 --- a/docs/mkdocs/docs/api/operator_literal_json_pointer.md +++ b/docs/mkdocs/docs/api/operator_literal_json_pointer.md @@ -17,7 +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. +[`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 @@ -58,6 +60,8 @@ Linear. ## See also - [json_pointer](json_pointer/index.md) - type to represent JSON Pointers +- [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 2bc8a4a5b..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 diff --git a/docs/mkdocs/docs/features/modules.md b/docs/mkdocs/docs/features/modules.md index 6708f1d81..32e9ba7fd 100644 --- a/docs/mkdocs/docs/features/modules.md +++ b/docs/mkdocs/docs/features/modules.md @@ -40,6 +40,9 @@ Only the following symbols are exported from `nlohmann.json`: - `nlohmann::literals::json_literals::operator""_json` - `nlohmann::literals::json_literals::operator""_json_pointer` +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, and should not be used directly: 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 70537bd27..21fad832a 100644 --- a/docs/mkdocs/mkdocs.yml +++ b/docs/mkdocs/mkdocs.yml @@ -293,6 +293,7 @@ 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 diff --git a/include/nlohmann/detail/macro_scope.hpp b/include/nlohmann/detail/macro_scope.hpp index 9c35cc3b7..0d524c710 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 03574f5bf..cb08777bc 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -6480,55 +6480,6 @@ std::string format_as(const NLOHMANN_BASIC_JSON_TPL& j) return j.dump(); } -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 NLOHMANN_JSON_NAMESPACE_END /////////////////////// @@ -6663,17 +6614,6 @@ struct formatter // NOLINT(cert-dcl58-c } // namespace std -#if JSON_USE_GLOBAL_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 @@ -6681,4 +6621,13 @@ 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 + // NOLINTNEXTLINE(misc-header-include-cycle): json_literals.hpp includes this header + #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..a865b6c82 --- /dev/null +++ b/include/nlohmann/json_literals.hpp @@ -0,0 +1,78 @@ +// __ _____ _____ _____ +// __| | __| | | | 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 + +// NOLINTNEXTLINE(misc-header-include-cycle): json.hpp includes this header at its end +#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. + +// declares the literal operator for the given suffix; GCC 4.8 requires a space +// between "" and the suffix, which newer compilers deprecate (CWG 2521) +#if !defined(__GNUC__) || defined(__clang__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9) + #define NLOHMANN_JSON_LITERAL_OPERATOR(suffix) operator""##suffix +#else + #define NLOHMANN_JSON_LITERAL_OPERATOR(suffix) operator"" suffix +#endif + +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/ +inline nlohmann::json NLOHMANN_JSON_LITERAL_OPERATOR(_json)(const char* s, std::size_t n) +{ + 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/ +inline nlohmann::json::json_pointer NLOHMANN_JSON_LITERAL_OPERATOR(_json_pointer)(const char* s, std::size_t n) +{ + 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 + using nlohmann::literals::json_literals::NLOHMANN_JSON_LITERAL_OPERATOR(_json); // NOLINT(misc-unused-using-decls,google-global-names-in-headers) + using nlohmann::literals::json_literals::NLOHMANN_JSON_LITERAL_OPERATOR(_json_pointer); //NOLINT(misc-unused-using-decls,google-global-names-in-headers) +#endif + +#undef NLOHMANN_JSON_LITERAL_OPERATOR + +#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 ef98ba71d..cf94c53a9 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -3329,10 +3329,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 @@ -33409,55 +33405,6 @@ std::string format_as(const NLOHMANN_BASIC_JSON_TPL& j) return j.dump(); } -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 NLOHMANN_JSON_NAMESPACE_END /////////////////////// @@ -33592,17 +33539,6 @@ struct formatter // NOLINT(cert-dcl58-c } // namespace std -#if JSON_USE_GLOBAL_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++ @@ -33631,7 +33567,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 @@ -33824,4 +33759,93 @@ 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 +// NOLINTNEXTLINE(misc-header-include-cycle): json_literals.hpp includes this header +// #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 + +// NOLINTNEXTLINE(misc-header-include-cycle): json.hpp includes this header at its end +// #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. + +// declares the literal operator for the given suffix; GCC 4.8 requires a space +// between "" and the suffix, which newer compilers deprecate (CWG 2521) +#if !defined(__GNUC__) || defined(__clang__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9) + #define NLOHMANN_JSON_LITERAL_OPERATOR(suffix) operator""##suffix +#else + #define NLOHMANN_JSON_LITERAL_OPERATOR(suffix) operator"" suffix +#endif + +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/ +inline nlohmann::json NLOHMANN_JSON_LITERAL_OPERATOR(_json)(const char* s, std::size_t n) +{ + 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/ +inline nlohmann::json::json_pointer NLOHMANN_JSON_LITERAL_OPERATOR(_json_pointer)(const char* s, std::size_t n) +{ + 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 + using nlohmann::literals::json_literals::NLOHMANN_JSON_LITERAL_OPERATOR(_json); // NOLINT(misc-unused-using-decls,google-global-names-in-headers) + using nlohmann::literals::json_literals::NLOHMANN_JSON_LITERAL_OPERATOR(_json_pointer); //NOLINT(misc-unused-using-decls,google-global-names-in-headers) +#endif + +#undef NLOHMANN_JSON_LITERAL_OPERATOR + +#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..a865b6c82 --- /dev/null +++ b/single_include/nlohmann/json_literals.hpp @@ -0,0 +1,78 @@ +// __ _____ _____ _____ +// __| | __| | | | 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 + +// NOLINTNEXTLINE(misc-header-include-cycle): json.hpp includes this header at its end +#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. + +// declares the literal operator for the given suffix; GCC 4.8 requires a space +// between "" and the suffix, which newer compilers deprecate (CWG 2521) +#if !defined(__GNUC__) || defined(__clang__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9) + #define NLOHMANN_JSON_LITERAL_OPERATOR(suffix) operator""##suffix +#else + #define NLOHMANN_JSON_LITERAL_OPERATOR(suffix) operator"" suffix +#endif + +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/ +inline nlohmann::json NLOHMANN_JSON_LITERAL_OPERATOR(_json)(const char* s, std::size_t n) +{ + 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/ +inline nlohmann::json::json_pointer NLOHMANN_JSON_LITERAL_OPERATOR(_json_pointer)(const char* s, std::size_t n) +{ + 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 + using nlohmann::literals::json_literals::NLOHMANN_JSON_LITERAL_OPERATOR(_json); // NOLINT(misc-unused-using-decls,google-global-names-in-headers) + using nlohmann::literals::json_literals::NLOHMANN_JSON_LITERAL_OPERATOR(_json_pointer); //NOLINT(misc-unused-using-decls,google-global-names-in-headers) +#endif + +#undef NLOHMANN_JSON_LITERAL_OPERATOR + +#endif // INCLUDE_NLOHMANN_JSON_LITERALS_HPP_ diff --git a/src/modules/json.cppm b/src/modules/json.cppm index 15207535f..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; diff --git a/tests/src/unit-no_automatic_udls.cpp b/tests/src/unit-no_automatic_udls.cpp new file mode 100644 index 000000000..1a708da50 --- /dev/null +++ b/tests/src/unit-no_automatic_udls.cpp @@ -0,0 +1,108 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ (supporting code) +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann +// SPDX-License-Identifier: MIT + +// 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" + +#include +#include + +#include +using json = nlohmann::json; + +// An argument type whose associated namespace is the library namespace, so +// 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_automatic_udls_probe +{ + operator const char* () const // NOLINT(google-explicit-constructor,hicpp-explicit-conversions) + { + return ""; + } +}; +NLOHMANN_JSON_NAMESPACE_END + +namespace +{ +// The calls below use a dependent argument, so a literal operator that is not +// declared at all is a substitution failure rather than a hard error: lookup is +// deferred to the point of instantiation, where it considers the declarations +// visible from here (the global using-declarations of JSON_USE_GLOBAL_UDLS) plus +// argument-dependent lookup (the literals in the library namespace). +#if !defined(__GNUC__) || defined(__clang__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9) + template + using json_udl_t = decltype(operator""_json(std::declval(), std::size_t())); + + template + using json_pointer_udl_t = decltype(operator""_json_pointer(std::declval(), std::size_t())); +#else + // GCC 4.8 requires a space between "" and suffix + template + using json_udl_t = decltype(operator"" _json(std::declval(), std::size_t())); + + template + using json_pointer_udl_t = decltype(operator"" _json_pointer(std::declval(), std::size_t())); +#endif + +template +using has_json_udl = nlohmann::detail::is_detected; + +template +using has_json_pointer_udl = nlohmann::detail::is_detected; +} // namespace + +TEST_CASE("JSON_NO_AUTOMATIC_UDLS") +{ + SECTION("literals are not declared") + { + // global namespace (JSON_USE_GLOBAL_UDLS defaults to 1) + CHECK_FALSE(has_json_udl::value); + CHECK_FALSE(has_json_pointer_udl::value); + + // nlohmann::literals::json_literals + CHECK_FALSE(has_json_udl::value); + CHECK_FALSE(has_json_pointer_udl::value); + } + + SECTION("the rest of the library keeps working") + { + const json j = json::parse(R"({"foo": {"bar": 42}})"); + CHECK(j.dump() == R"({"foo":{"bar":42}})"); + + const json::json_pointer ptr("/foo/bar"); + CHECK(j.at(ptr) == 42); + CHECK(j.contains(ptr)); + } +} + +// the literals can still be added where they are needed +#include + +TEST_CASE("JSON_NO_AUTOMATIC_UDLS with ") +{ +#if !defined(JSON_USE_GLOBAL_UDLS) || JSON_USE_GLOBAL_UDLS + SECTION("global namespace") + { + CHECK("[1,2]"_json == json({1, 2})); + CHECK("/a/0"_json_pointer == json::json_pointer("/a/0")); + } +#endif + + 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); + } +}