Files
json/docs/mkdocs/docs/api/basic_json/number_unsigned_t.md
T
Niels Lohmann ce28c722bc Allow the same type for number_integer_t and number_unsigned_t (#5815)
* Allow the same type for number_integer_t and number_unsigned_t

basic_json did not compile with NumberUnsignedType == NumberIntegerType
because overloads on both types collided. Such a basic_json now stores
every integer as number_integer: the colliding overloads take a
placeholder type, unsigned C++ integers are converted to number_integer_t,
and value_t::number_unsigned maps to number_integer.

Also fixes two problems this configuration would hit: the unsigned
integer parser accepted values that wrap around to negative numbers, and
dump() overflowed when computing the absolute value of the minimum.

A repeated NumberFloatType gets a static_assert.

Refs #2573

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Use json::with_integers_t in the test and the docs

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* ✅ skip patch test on GCC 5 to avoid internal compiler error

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Fix CI: name the unsigned overload type through template parameters

basic_json used number_unsigned_overload_t<basic_json> while the class was
still incomplete. MSVC rejected it as a recursive alias declaration and GCC
4.9, 5 and 7 crashed with an internal compiler error. basic_json now uses
number_unsigned_overload_type<NumberIntegerType, NumberUnsignedType>, which
also makes the GCC 5 workaround in the patch test unnecessary.

Infer reported a null dereference for the number_unsigned case in
from_json, which cannot happen for a basic_json whose number_unsigned_t is
number_integer_t; assert it.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Address review: conjunction/negation trait, astyle-friendly alias, docs table order

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-15 20:04:42 +02:00

4.2 KiB

nlohmann::basic_json::number_unsigned_t

using number_unsigned_t = NumberUnsignedType;

The type used to store JSON numbers (unsigned).

RFC 8259 describes numbers as follows:

The representation of numbers is similar to that used in most programming languages. A number is represented in base 10 using decimal digits. It contains an integer component that may be prefixed with an optional minus sign, which may be followed by a fraction part and/or an exponent part. Leading zeros are not allowed. (...) Numeric values that cannot be represented in the grammar below (such as Infinity and NaN) are not permitted.

This description includes both integer and floating-point numbers. However, C++ allows more precise storage if it is known whether the number is a signed integer, an unsigned integer, or a floating-point number. Therefore, three different types, number_integer_t, number_unsigned_t and number_float_t are used.

To store unsigned integer numbers in C++, a type is defined by the template parameter NumberUnsignedType which chooses the type to use.

Template parameters

NumberUnsignedType
the type to store unsigned integers. It must be an unsigned integral type (#!cpp std::is_integral) with a #!cpp std::numeric_limits specialization, and it must be able to represent the absolute value of every number_integer_t value. Alternatively, it can be the same type as number_integer_t; then every integer is stored as number_integer_t. See Template Parameter Requirements.

Notes

Default type

With the default values for NumberUnsignedType (std::uint64_t), the default type for number_unsigned_t is #!cpp std::uint64_t.

Default behavior

  • The restrictions about leading zeros are not enforced in C++. Instead, leading zeros in integer literals lead to an interpretation as an octal number. Internally, the value will be stored as a decimal number. For instance, the C++ integer literal 010 will be serialized to 8. During deserialization, leading zeros yield an error.

Limits

RFC 8259 specifies:

An implementation may set limits on the range and precision of numbers.

When the default type is used, the maximal integer number that can be stored is 18446744073709551615 (UINT64_MAX) and the minimal integer number that can be stored is 0. Integer numbers that are out of range will yield over/underflow when used in a constructor. During deserialization (from JSON text or any of the binary formats), too large or small integer numbers will automatically be stored as number_integer_t or number_float_t.

RFC 8259 further states:

Note that when such software is used, numbers that are integers and are in the range [-253+1, 253-1] are interoperable in the sense that implementations will agree exactly on their numeric values.

As this range is a subrange (when considered in conjunction with the number_integer_t type) of the exactly supported range [0, UINT64_MAX], this class's integer type is interoperable.

Storage

Integer number values are stored directly inside a basic_json type.

Examples

??? example

The following code shows that `number_unsigned_t` is by default, a typedef to `#!cpp std::uint64_t`.
 
```cpp
--8<-- "examples/number_unsigned_t.cpp"
```

Output:

```json
--8<-- "examples/number_unsigned_t.output"
```

See also

Version history

  • Added in version 2.0.0.
  • Can be the same type as number_integer_t since version 3.13.0.