Question
Why does
json j{true};
and
json j(true);
yield different results ([true] vs. true)?
This is a known issue, and -- even worse -- the behavior differs between GCC and Clang. The “culprit” for this is the library's constructor overloads for initializer lists to allow syntax like
json array = {1, 2, 3, 4};
for arrays and
json object = {{"one", 1}, {"two", 2}};
for objects.
Tip
To avoid any confusion and ensure portable code, do not use brace initialization with the types basic_json, json, or ordered_json unless you want to create an object or array as shown in the examples above.
To explicitly create a single-element array, use json::array({value}):
json j = json::array({true}); // [true]
Opt-in copy semantics (since version 3.12.0)
If you define JSON_BRACE_INIT_COPY_SEMANTICS to 1 before including the library, single-element brace initialization is treated as copy/move instead of creating a single-element array:
#define JSON_BRACE_INIT_COPY_SEMANTICS 1
#include <nlohmann/json.hpp>
json obj = {{"key", "value"}};
json j{obj}; // -> {"key":"value"} (copy, not array)
Without the macro (default behavior), json j{obj} creates [{"key":"value"}]. This opt-in macro fixes issue #5074 while preserving backwards compatibility for existing code.
Question
Can you add an option to ignore trailing commas?
This library does not support any feature that would jeopardize interoperability.
Questions
[json.exception.parse_error.101] parse error at line 1, column 53: syntax error while parsing value - invalid string: ill-formed UTF-8 byte; last read: '"Testé$')"The library supports Unicode input as follows:
std::u16string and std::u32string can be parsed, assuming UTF-16 and UTF-32 encoding, respectively. These encodings are not supported when reading from files or other input containers.\uDEAD) will yield parse errors.std::string), note that its length/size functions return the number of stored bytes rather than the number of characters or glyphs.dump() may throw an exception unless json::error_handler_t::replace or json::error_handler_t::ignore are used as error handlers.In most cases, the parser is right to complain, because the input is not UTF-8 encoded. This is especially true for Microsoft Windows, where Latin-1 or ISO 8859-1 is often the standard encoding.
Question
Why are wide strings (e.g., std::wstring) dumped as arrays of numbers?
As described above, the library assumes UTF-8 as encoding. To store a wide string, you need to change the encoding.
Example
#include <codecvt> // codecvt_utf8
#include <locale> // wstring_convert
// encoding function
std::string to_utf8(std::wstring& wide_string)
{
static std::wstring_convert<std::codecvt_utf8<wchar_t>> utf8_conv;
return utf8_conv.to_bytes(wide_string);
}
json j;
std::wstring ws = L"車B1234 こんにちは";
j["original"] = ws;
j["encoded"] = to_utf8(ws);
std::cout << j << std::endl;
The result is:
{
"encoded": "車B1234 こんにちは",
"original": [36554, 66, 49, 50, 51, 52, 32, 12371, 12435, 12395, 12385, 12399]
}
Question
Is basic_json thread-safe?
No. basic_json provides no built-in synchronization, the same as std::map or std::vector. Concurrent reads of the same value from multiple threads are safe, as are concurrent (non-overlapping) accesses to independent json objects. However, any concurrent write to a json object -- or a concurrent read while another thread writes to the same object -- is a data race and requires external synchronization (e.g., a std::mutex) by the caller.
Question
Does this library support JSON Schema validation?
Not directly, but the companion project json-schema-validator builds JSON Schema (draft 4, 6, 7, and 2019-09) validation on top of this library and is a common recommendation for this use case.
Question
Is it possible to indicate a parse error without throwing an exception?
Yes, see Parsing and exceptions.
Question
Can I get the key of the object item that caused an exception?
Yes, you can. Please define the symbol JSON_DIAGNOSTICS to get extended diagnostics messages.
Question
The library uses std::numeric_limits<number_float_t>::digits10 (15 for IEEE doubles) digits for serialization. This value is sufficient to guarantee roundtripping. If one uses more than this number of digits of precision, then string -> value -> string is not guaranteed to round-trip.
The value of std::numeric_limits<T>::digits10 is the number of base-10 digits that can be represented by the type T without change, that is, any number with this many significant decimal digits can be converted to a value of type T and back to decimal form, without change due to rounding or overflow.
Tip
The website https://float.exposed gives a good insight into the internal storage of floating-point numbers.
See this section on the library's number handling for more information.
std::format or fmtQuestion
std::format("{}", j) on a JSON value?fmt::format("{}", j) or fmt::print("{}", j) (the {fmt} library) on a JSON value?std::format works out of the box since version 3.13.0, as long as the standard library provides <format> (see JSON_HAS_STD_FORMAT); see std::formatter<basic_json> for details, including the "{:#}" pretty-print spec, indent widths ("{:2}"), and custom indent characters ("{:.>#}").
For fmt, the library ships format_as, a small customization point fmt looks for via argument-dependent lookup. It only has an effect on fmt 10.0.0 through 11.0.2 — from fmt 11.1.0 onwards, fmt no longer picks up a format_as overload that returns a std::string. On such versions (or any version, if you also want the same "{:#}"/width/fill-and-align spec support that std::formatter<basic_json> has), define your own fmt::formatter specialization; see format_as for a recipe that mirrors it.
If you get ambiguous-overload errors when passing a JSON value to fmt::format/fmt::print without any fmt::formatter<json> specialization in scope, that's fmt picking up basic_json's implicit operator ValueType() conversion operator (see #964 and #958); disabling it via JSON_USE_IMPLICIT_CONVERSIONS 0 avoids the ambiguity.
Question
Why does the code not compile with Android SDK?
Android defaults to using very old compilers and C++ libraries. To fix this, add the following to your Application.mk. This will switch to the LLVM C++ library, the Clang compiler, and enable C++11 and other features disabled by default.
APP_STL := c++_shared NDK_TOOLCHAIN_VERSION := clang3.6 APP_CPPFLAGS += -frtti -fexceptions
The code compiles successfully with Android NDK, Revision 9 - 11 (and possibly later) and CrystaX's Android NDK version 10.
Questions
'to_string' is not a member of 'std' (or similarly, for strtod or strtof)?This is not an issue with the code, but rather with the compiler itself. On Android, see above to build with a newer environment. For MinGW, please refer to this site and this discussion for information on how to fix this bug. For Android NDK using APP_STL := gnustl_static, please refer to this discussion.