Compare commits

...
Author SHA1 Message Date
Niels Lohmann 6c5464681c Merge branch 'develop' into fix/scalar-comparison-noexcept
Conflict in operator_ne.md: took develop's corrected page (#5638 documents that there is no C++20 member operator!=) and re-added this branch's conditional noexcept for overload (2) and its version history note. Ran make amalgamate.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-02 11:49:43 +02:00
Niels Lohmann c0694f7966 Make comparisons with scalars noexcept only when the conversion is
The comparison operators taking a scalar (==, !=, <, <=, >, >=, and
C++20's <=>) convert the scalar to a basic_json and compare, but were
unconditionally noexcept. When that conversion throws, the program
called std::terminate instead of propagating the exception, e.g. when
comparing a json with a string literal under memory pressure
(std::bad_alloc) or with an enum value not mapped by
NLOHMANN_JSON_SERIALIZE_ENUM_STRICT (out_of_range.410). clang-tidy
22.1 reports the latter as bugprone-exception-escape.

Declare the 16 scalar overloads
noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value):
they stay noexcept for numbers, Booleans, nullptr, and plain enums,
and are noexcept(false) for strings and enums whose to_json may throw.
The comparisons of two basic_json values are unchanged.

Restore the strict-enum comparisons removed from unit-conversions.cpp
in the previous PR, check that comparing an unmapped strict enum now
throws, and pin the new exception specifications in unit-noexcept.cpp.
Document the exception safety of overload (2) on all seven operator
pages. Ran make amalgamate.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-02 11:23:58 +02:00
11 changed files with 125 additions and 53 deletions
+10 -4
View File
@@ -5,17 +5,17 @@
bool operator==(const_reference lhs, const_reference rhs) noexcept; // (1) bool operator==(const_reference lhs, const_reference rhs) noexcept; // (1)
template<typename ScalarType> template<typename ScalarType>
bool operator==(const_reference lhs, const ScalarType rhs) noexcept; // (2) bool operator==(const_reference lhs, const ScalarType rhs) noexcept(/* see below */); // (2)
template<typename ScalarType> template<typename ScalarType>
bool operator==(ScalarType lhs, const const_reference rhs) noexcept; // (2) bool operator==(ScalarType lhs, const const_reference rhs) noexcept(/* see below */); // (2)
// since C++20 // since C++20
class basic_json { class basic_json {
bool operator==(const_reference rhs) const noexcept; // (1) bool operator==(const_reference rhs) const noexcept; // (1)
template<typename ScalarType> template<typename ScalarType>
bool operator==(ScalarType rhs) const noexcept; // (2) bool operator==(ScalarType rhs) const noexcept(/* see below */); // (2)
}; };
``` ```
@@ -46,7 +46,12 @@ whether the values `lhs`/`*this` and `rhs` are equal
## Exception safety ## Exception safety
No-throw guarantee: this function never throws exceptions. 1. No-throw guarantee: this function never throws exceptions.
2. No-throw guarantee if converting the scalar to a JSON value cannot throw, as for numbers, Booleans, and
`#!cpp nullptr`; the function is `#!cpp noexcept` exactly in that case. Otherwise, it throws what the conversion
throws, for example `std::bad_alloc` when converting a string, or
[`out_of_range.410`](../../home/exceptions.md#jsonexceptionout_of_range410) for an enum value not mapped by
[`NLOHMANN_JSON_SERIALIZE_ENUM_STRICT`](../macros/nlohmann_json_serialize_enum_strict.md).
## Complexity ## Complexity
@@ -171,3 +176,4 @@ Linear.
1. Added in version 1.0.0. Added C++20 member functions in version 3.11.0. 1. Added in version 1.0.0. Added C++20 member functions in version 3.11.0.
2. Added in version 1.0.0. Added C++20 member functions in version 3.11.0. 2. Added in version 1.0.0. Added C++20 member functions in version 3.11.0.
Made conditionally `#!cpp noexcept` in version 3.13.0; before, a throwing conversion called `std::terminate`.
@@ -5,10 +5,10 @@
bool operator>=(const_reference lhs, const_reference rhs) noexcept; // (1) bool operator>=(const_reference lhs, const_reference rhs) noexcept; // (1)
template<typename ScalarType> template<typename ScalarType>
bool operator>=(const_reference lhs, const ScalarType rhs) noexcept; // (2) bool operator>=(const_reference lhs, const ScalarType rhs) noexcept(/* see below */); // (2)
template<typename ScalarType> template<typename ScalarType>
bool operator>=(ScalarType lhs, const const_reference rhs) noexcept; // (2) bool operator>=(ScalarType lhs, const const_reference rhs) noexcept(/* see below */); // (2)
``` ```
1. Compares whether one JSON value `lhs` is greater than or equal to another JSON value `rhs` according to the following 1. Compares whether one JSON value `lhs` is greater than or equal to another JSON value `rhs` according to the following
@@ -39,7 +39,12 @@ whether `lhs` is greater than or equal to `rhs`
## Exception safety ## Exception safety
No-throw guarantee: this function never throws exceptions. 1. No-throw guarantee: this function never throws exceptions.
2. No-throw guarantee if converting the scalar to a JSON value cannot throw, as for numbers, Booleans, and
`#!cpp nullptr`; the function is `#!cpp noexcept` exactly in that case. Otherwise, it throws what the conversion
throws, for example `std::bad_alloc` when converting a string, or
[`out_of_range.410`](../../home/exceptions.md#jsonexceptionout_of_range410) for an enum value not mapped by
[`NLOHMANN_JSON_SERIALIZE_ENUM_STRICT`](../macros/nlohmann_json_serialize_enum_strict.md).
## Complexity ## Complexity
@@ -94,3 +99,4 @@ Linear.
1. Added in version 1.0.0. Conditionally removed since C++20 in version 3.11.0. 1. Added in version 1.0.0. Conditionally removed since C++20 in version 3.11.0.
2. Added in version 1.0.0. Conditionally removed since C++20 in version 3.11.0. 2. Added in version 1.0.0. Conditionally removed since C++20 in version 3.11.0.
Made conditionally `#!cpp noexcept` in version 3.13.0; before, a throwing conversion called `std::terminate`.
@@ -5,10 +5,10 @@
bool operator>(const_reference lhs, const_reference rhs) noexcept; // (1) bool operator>(const_reference lhs, const_reference rhs) noexcept; // (1)
template<typename ScalarType> template<typename ScalarType>
bool operator>(const_reference lhs, const ScalarType rhs) noexcept; // (2) bool operator>(const_reference lhs, const ScalarType rhs) noexcept(/* see below */); // (2)
template<typename ScalarType> template<typename ScalarType>
bool operator>(ScalarType lhs, const const_reference rhs) noexcept; // (2) bool operator>(ScalarType lhs, const const_reference rhs) noexcept(/* see below */); // (2)
``` ```
1. Compares whether one JSON value `lhs` is greater than another JSON value `rhs` according to the 1. Compares whether one JSON value `lhs` is greater than another JSON value `rhs` according to the
@@ -39,7 +39,12 @@ whether `lhs` is greater than `rhs`
## Exception safety ## Exception safety
No-throw guarantee: this function never throws exceptions. 1. No-throw guarantee: this function never throws exceptions.
2. No-throw guarantee if converting the scalar to a JSON value cannot throw, as for numbers, Booleans, and
`#!cpp nullptr`; the function is `#!cpp noexcept` exactly in that case. Otherwise, it throws what the conversion
throws, for example `std::bad_alloc` when converting a string, or
[`out_of_range.410`](../../home/exceptions.md#jsonexceptionout_of_range410) for an enum value not mapped by
[`NLOHMANN_JSON_SERIALIZE_ENUM_STRICT`](../macros/nlohmann_json_serialize_enum_strict.md).
## Complexity ## Complexity
@@ -84,3 +89,4 @@ Linear.
1. Added in version 1.0.0. Conditionally removed since C++20 in version 3.11.0. 1. Added in version 1.0.0. Conditionally removed since C++20 in version 3.11.0.
2. Added in version 1.0.0. Conditionally removed since C++20 in version 3.11.0. 2. Added in version 1.0.0. Conditionally removed since C++20 in version 3.11.0.
Made conditionally `#!cpp noexcept` in version 3.13.0; before, a throwing conversion called `std::terminate`.
@@ -5,10 +5,10 @@
bool operator<=(const_reference lhs, const_reference rhs) noexcept; // (1) bool operator<=(const_reference lhs, const_reference rhs) noexcept; // (1)
template<typename ScalarType> template<typename ScalarType>
bool operator<=(const_reference lhs, const ScalarType rhs) noexcept; // (2) bool operator<=(const_reference lhs, const ScalarType rhs) noexcept(/* see below */); // (2)
template<typename ScalarType> template<typename ScalarType>
bool operator<=(ScalarType lhs, const const_reference rhs) noexcept; // (2) bool operator<=(ScalarType lhs, const const_reference rhs) noexcept(/* see below */); // (2)
``` ```
1. Compares whether one JSON value `lhs` is less than or equal to another JSON value `rhs` 1. Compares whether one JSON value `lhs` is less than or equal to another JSON value `rhs`
@@ -40,7 +40,12 @@ whether `lhs` is less than or equal to `rhs`
## Exception safety ## Exception safety
No-throw guarantee: this function never throws exceptions. 1. No-throw guarantee: this function never throws exceptions.
2. No-throw guarantee if converting the scalar to a JSON value cannot throw, as for numbers, Booleans, and
`#!cpp nullptr`; the function is `#!cpp noexcept` exactly in that case. Otherwise, it throws what the conversion
throws, for example `std::bad_alloc` when converting a string, or
[`out_of_range.410`](../../home/exceptions.md#jsonexceptionout_of_range410) for an enum value not mapped by
[`NLOHMANN_JSON_SERIALIZE_ENUM_STRICT`](../macros/nlohmann_json_serialize_enum_strict.md).
## Complexity ## Complexity
@@ -95,3 +100,4 @@ Linear.
1. Added in version 1.0.0. Conditionally removed since C++20 in version 3.11.0. 1. Added in version 1.0.0. Conditionally removed since C++20 in version 3.11.0.
2. Added in version 1.0.0. Conditionally removed since C++20 in version 3.11.0. 2. Added in version 1.0.0. Conditionally removed since C++20 in version 3.11.0.
Made conditionally `#!cpp noexcept` in version 3.13.0; before, a throwing conversion called `std::terminate`.
@@ -5,10 +5,10 @@
bool operator<(const_reference lhs, const_reference rhs) noexcept; // (1) bool operator<(const_reference lhs, const_reference rhs) noexcept; // (1)
template<typename ScalarType> template<typename ScalarType>
bool operator<(const_reference lhs, const ScalarType rhs) noexcept; // (2) bool operator<(const_reference lhs, const ScalarType rhs) noexcept(/* see below */); // (2)
template<typename ScalarType> template<typename ScalarType>
bool operator<(ScalarType lhs, const const_reference rhs) noexcept; // (2) bool operator<(ScalarType lhs, const const_reference rhs) noexcept(/* see below */); // (2)
``` ```
1. Compares whether one JSON value `lhs` is less than another JSON value `rhs` according to the 1. Compares whether one JSON value `lhs` is less than another JSON value `rhs` according to the
@@ -49,7 +49,12 @@ whether `lhs` is less than `rhs`
## Exception safety ## Exception safety
No-throw guarantee: this function never throws exceptions. 1. No-throw guarantee: this function never throws exceptions.
2. No-throw guarantee if converting the scalar to a JSON value cannot throw, as for numbers, Booleans, and
`#!cpp nullptr`; the function is `#!cpp noexcept` exactly in that case. Otherwise, it throws what the conversion
throws, for example `std::bad_alloc` when converting a string, or
[`out_of_range.410`](../../home/exceptions.md#jsonexceptionout_of_range410) for an enum value not mapped by
[`NLOHMANN_JSON_SERIALIZE_ENUM_STRICT`](../macros/nlohmann_json_serialize_enum_strict.md).
## Complexity ## Complexity
@@ -94,3 +99,4 @@ Linear.
1. Added in version 1.0.0. Conditionally removed since C++20 in version 3.11.0. 1. Added in version 1.0.0. Conditionally removed since C++20 in version 3.11.0.
2. Added in version 1.0.0. Conditionally removed since C++20 in version 3.11.0. 2. Added in version 1.0.0. Conditionally removed since C++20 in version 3.11.0.
Made conditionally `#!cpp noexcept` in version 3.13.0; before, a throwing conversion called `std::terminate`.
@@ -5,10 +5,10 @@
bool operator!=(const_reference lhs, const_reference rhs) noexcept; // (1) bool operator!=(const_reference lhs, const_reference rhs) noexcept; // (1)
template<typename ScalarType> template<typename ScalarType>
bool operator!=(const_reference lhs, const ScalarType rhs) noexcept; // (2) bool operator!=(const_reference lhs, const ScalarType rhs) noexcept(/* see below */); // (2)
template<typename ScalarType> template<typename ScalarType>
bool operator!=(ScalarType lhs, const const_reference rhs) noexcept; // (2) bool operator!=(ScalarType lhs, const const_reference rhs) noexcept(/* see below */); // (2)
``` ```
1. Compares two JSON values for inequality. Returns `#!cpp !(lhs == rhs)`. 1. Compares two JSON values for inequality. Returns `#!cpp !(lhs == rhs)`.
@@ -36,7 +36,12 @@ whether the values `lhs`/`*this` and `rhs` are not equal
## Exception safety ## Exception safety
No-throw guarantee: this function never throws exceptions. 1. No-throw guarantee: this function never throws exceptions.
2. No-throw guarantee if converting the scalar to a JSON value cannot throw, as for numbers, Booleans, and
`#!cpp nullptr`; the function is `#!cpp noexcept` exactly in that case. Otherwise, it throws what the conversion
throws, for example `std::bad_alloc` when converting a string, or
[`out_of_range.410`](../../home/exceptions.md#jsonexceptionout_of_range410) for an enum value not mapped by
[`NLOHMANN_JSON_SERIALIZE_ENUM_STRICT`](../macros/nlohmann_json_serialize_enum_strict.md).
## Complexity ## Complexity
@@ -98,3 +103,4 @@ Linear.
member function in version 3.13.0; since C++20, the compiler rewrites `a != b` using `operator==`. member function in version 3.13.0; since C++20, the compiler rewrites `a != b` using `operator==`.
2. Added in version 1.0.0. Changed in version 3.13.0 to remove special-casing for `NaN` and `discarded` values; 2. Added in version 1.0.0. Changed in version 3.13.0 to remove special-casing for `NaN` and `discarded` values;
`operator!=` now consistently means `!(a == b)`. Since C++20, the compiler rewrites `a != b` using `operator==`. `operator!=` now consistently means `!(a == b)`. Since C++20, the compiler rewrites `a != b` using `operator==`.
Made conditionally `#!cpp noexcept` in version 3.13.0; before, a throwing conversion called `std::terminate`.
@@ -6,7 +6,7 @@ class basic_json {
std::partial_ordering operator<=>(const_reference rhs) const noexcept; // (1) std::partial_ordering operator<=>(const_reference rhs) const noexcept; // (1)
template<typename ScalarType> template<typename ScalarType>
std::partial_ordering operator<=>(const ScalarType rhs) const noexcept; // (2) std::partial_ordering operator<=>(const ScalarType rhs) const noexcept(/* see below */); // (2)
}; };
``` ```
@@ -39,7 +39,12 @@ the `std::partial_ordering` of the 3-way comparison of `*this` and `rhs`
## Exception safety ## Exception safety
No-throw guarantee: this function never throws exceptions. 1. No-throw guarantee: this function never throws exceptions.
2. No-throw guarantee if converting the scalar to a JSON value cannot throw, as for numbers, Booleans, and
`#!cpp nullptr`; the function is `#!cpp noexcept` exactly in that case. Otherwise, it throws what the conversion
throws, for example `std::bad_alloc` when converting a string, or
[`out_of_range.410`](../../home/exceptions.md#jsonexceptionout_of_range410) for an enum value not mapped by
[`NLOHMANN_JSON_SERIALIZE_ENUM_STRICT`](../macros/nlohmann_json_serialize_enum_strict.md).
## Complexity ## Complexity
@@ -98,3 +103,4 @@ Linear.
1. Added in version 3.11.0. 1. Added in version 3.11.0.
2. Added in version 3.11.0. 2. Added in version 3.11.0.
Made conditionally `#!cpp noexcept` in version 3.13.0; before, a throwing conversion called `std::terminate`.
+16 -16
View File
@@ -4865,7 +4865,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
template<typename ScalarType> template<typename ScalarType>
requires std::is_scalar_v<ScalarType> requires std::is_scalar_v<ScalarType>
bool operator==(ScalarType rhs) const noexcept bool operator==(ScalarType rhs) const noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return *this == basic_json(rhs); return *this == basic_json(rhs);
} }
@@ -4888,7 +4888,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/ /// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/
template<typename ScalarType> template<typename ScalarType>
requires std::is_scalar_v<ScalarType> requires std::is_scalar_v<ScalarType>
std::partial_ordering operator<=>(ScalarType rhs) const noexcept // *NOPAD* std::partial_ordering operator<=>(ScalarType rhs) const noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) // *NOPAD*
{ {
return *this <=> basic_json(rhs); // *NOPAD* return *this <=> basic_json(rhs); // *NOPAD*
} }
@@ -4913,7 +4913,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_le/ /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
template<typename ScalarType> template<typename ScalarType>
requires std::is_scalar_v<ScalarType> requires std::is_scalar_v<ScalarType>
bool operator<=(ScalarType rhs) const noexcept bool operator<=(ScalarType rhs) const noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return *this <= basic_json(rhs); return *this <= basic_json(rhs);
} }
@@ -4934,7 +4934,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
template<typename ScalarType> template<typename ScalarType>
requires std::is_scalar_v<ScalarType> requires std::is_scalar_v<ScalarType>
bool operator>=(ScalarType rhs) const noexcept bool operator>=(ScalarType rhs) const noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return *this >= basic_json(rhs); return *this >= basic_json(rhs);
} }
@@ -4959,7 +4959,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator==(const_reference lhs, ScalarType rhs) noexcept friend bool operator==(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return lhs == basic_json(rhs); return lhs == basic_json(rhs);
} }
@@ -4968,7 +4968,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator==(ScalarType lhs, const_reference rhs) noexcept friend bool operator==(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return basic_json(lhs) == rhs; return basic_json(lhs) == rhs;
} }
@@ -4984,7 +4984,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ne/ /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return lhs != basic_json(rhs); return lhs != basic_json(rhs);
} }
@@ -4993,7 +4993,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ne/ /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return basic_json(lhs) != rhs; return basic_json(lhs) != rhs;
} }
@@ -5013,7 +5013,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_lt/ /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<(const_reference lhs, ScalarType rhs) noexcept friend bool operator<(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return lhs < basic_json(rhs); return lhs < basic_json(rhs);
} }
@@ -5022,7 +5022,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_lt/ /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<(ScalarType lhs, const_reference rhs) noexcept friend bool operator<(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return basic_json(lhs) < rhs; return basic_json(lhs) < rhs;
} }
@@ -5042,7 +5042,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_le/ /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return lhs <= basic_json(rhs); return lhs <= basic_json(rhs);
} }
@@ -5051,7 +5051,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_le/ /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return basic_json(lhs) <= rhs; return basic_json(lhs) <= rhs;
} }
@@ -5072,7 +5072,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_gt/ /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>(const_reference lhs, ScalarType rhs) noexcept friend bool operator>(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return lhs > basic_json(rhs); return lhs > basic_json(rhs);
} }
@@ -5081,7 +5081,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_gt/ /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>(ScalarType lhs, const_reference rhs) noexcept friend bool operator>(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return basic_json(lhs) > rhs; return basic_json(lhs) > rhs;
} }
@@ -5101,7 +5101,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return lhs >= basic_json(rhs); return lhs >= basic_json(rhs);
} }
@@ -5110,7 +5110,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return basic_json(lhs) >= rhs; return basic_json(lhs) >= rhs;
} }
+16 -16
View File
@@ -31564,7 +31564,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
template<typename ScalarType> template<typename ScalarType>
requires std::is_scalar_v<ScalarType> requires std::is_scalar_v<ScalarType>
bool operator==(ScalarType rhs) const noexcept bool operator==(ScalarType rhs) const noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return *this == basic_json(rhs); return *this == basic_json(rhs);
} }
@@ -31587,7 +31587,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/ /// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/
template<typename ScalarType> template<typename ScalarType>
requires std::is_scalar_v<ScalarType> requires std::is_scalar_v<ScalarType>
std::partial_ordering operator<=>(ScalarType rhs) const noexcept // *NOPAD* std::partial_ordering operator<=>(ScalarType rhs) const noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) // *NOPAD*
{ {
return *this <=> basic_json(rhs); // *NOPAD* return *this <=> basic_json(rhs); // *NOPAD*
} }
@@ -31612,7 +31612,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_le/ /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
template<typename ScalarType> template<typename ScalarType>
requires std::is_scalar_v<ScalarType> requires std::is_scalar_v<ScalarType>
bool operator<=(ScalarType rhs) const noexcept bool operator<=(ScalarType rhs) const noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return *this <= basic_json(rhs); return *this <= basic_json(rhs);
} }
@@ -31633,7 +31633,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
template<typename ScalarType> template<typename ScalarType>
requires std::is_scalar_v<ScalarType> requires std::is_scalar_v<ScalarType>
bool operator>=(ScalarType rhs) const noexcept bool operator>=(ScalarType rhs) const noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return *this >= basic_json(rhs); return *this >= basic_json(rhs);
} }
@@ -31658,7 +31658,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator==(const_reference lhs, ScalarType rhs) noexcept friend bool operator==(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return lhs == basic_json(rhs); return lhs == basic_json(rhs);
} }
@@ -31667,7 +31667,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator==(ScalarType lhs, const_reference rhs) noexcept friend bool operator==(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return basic_json(lhs) == rhs; return basic_json(lhs) == rhs;
} }
@@ -31683,7 +31683,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ne/ /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return lhs != basic_json(rhs); return lhs != basic_json(rhs);
} }
@@ -31692,7 +31692,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ne/ /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return basic_json(lhs) != rhs; return basic_json(lhs) != rhs;
} }
@@ -31712,7 +31712,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_lt/ /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<(const_reference lhs, ScalarType rhs) noexcept friend bool operator<(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return lhs < basic_json(rhs); return lhs < basic_json(rhs);
} }
@@ -31721,7 +31721,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_lt/ /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<(ScalarType lhs, const_reference rhs) noexcept friend bool operator<(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return basic_json(lhs) < rhs; return basic_json(lhs) < rhs;
} }
@@ -31741,7 +31741,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_le/ /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return lhs <= basic_json(rhs); return lhs <= basic_json(rhs);
} }
@@ -31750,7 +31750,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_le/ /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return basic_json(lhs) <= rhs; return basic_json(lhs) <= rhs;
} }
@@ -31771,7 +31771,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_gt/ /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>(const_reference lhs, ScalarType rhs) noexcept friend bool operator>(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return lhs > basic_json(rhs); return lhs > basic_json(rhs);
} }
@@ -31780,7 +31780,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_gt/ /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>(ScalarType lhs, const_reference rhs) noexcept friend bool operator>(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return basic_json(lhs) > rhs; return basic_json(lhs) > rhs;
} }
@@ -31800,7 +31800,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return lhs >= basic_json(rhs); return lhs >= basic_json(rhs);
} }
@@ -31809,7 +31809,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return basic_json(lhs) >= rhs; return basic_json(lhs) >= rhs;
} }
+21
View File
@@ -1764,6 +1764,12 @@ TEST_CASE("Strict JSON to enum mapping")
CHECK(json("herz").get<strict_cards>() == strict_cards::herz); CHECK(json("herz").get<strict_cards>() == strict_cards::herz);
CHECK(json("karo").get<strict_cards>() == strict_cards::karo); CHECK(json("karo").get<strict_cards>() == strict_cards::karo);
// comparison of enum and json
CHECK(strict_cards::kreuz == json("kreuz"));
CHECK(strict_cards::pik == json("pik"));
CHECK(strict_cards::herz == json("herz"));
CHECK(strict_cards::karo == json("karo"));
// invalid json -> exception thrown // invalid json -> exception thrown
json _; json _;
CHECK_THROWS_WITH_AS(_ = json("what?").get<strict_cards>(), "[json.exception.out_of_range.410] enum value out of range for strict_cards: \"what?\"", json::out_of_range&); CHECK_THROWS_WITH_AS(_ = json("what?").get<strict_cards>(), "[json.exception.out_of_range.410] enum value out of range for strict_cards: \"what?\"", json::out_of_range&);
@@ -1771,6 +1777,12 @@ TEST_CASE("Strict JSON to enum mapping")
// conversion of unmapped enum -> exception thrown // conversion of unmapped enum -> exception thrown
CHECK_THROWS_WITH_AS(json(strict_cards::andere), "[json.exception.out_of_range.410] enum value out of range for strict_cards", json::out_of_range&); CHECK_THROWS_WITH_AS(json(strict_cards::andere), "[json.exception.out_of_range.410] enum value out of range for strict_cards", json::out_of_range&);
// comparing an unmapped enum with json throws the same exception
// (the scalar comparison operators used to be noexcept, so this
// called std::terminate)
CHECK_THROWS_WITH_AS(static_cast<void>(strict_cards::andere == json("andere")), "[json.exception.out_of_range.410] enum value out of range for strict_cards", json::out_of_range&);
CHECK_THROWS_WITH_AS(static_cast<void>(json("andere") != strict_cards::andere), "[json.exception.out_of_range.410] enum value out of range for strict_cards", json::out_of_range&);
// invalid UTF-8 -> out_of_range.410, not the type_error.316 thrown while building the // invalid UTF-8 -> out_of_range.410, not the type_error.316 thrown while building the
// message (regression test for #5667); such strings can reach get<Enum>() unvalidated, // message (regression test for #5667); such strings can reach get<Enum>() unvalidated,
// e.g. from from_cbor()/from_msgpack() (#5529) // e.g. from from_cbor()/from_msgpack() (#5529)
@@ -1792,12 +1804,21 @@ TEST_CASE("Strict JSON to enum mapping")
CHECK(json("completed").get<StrictTaskState>() == STRICT_TS_COMPLETED); CHECK(json("completed").get<StrictTaskState>() == STRICT_TS_COMPLETED);
CHECK(json().get<StrictTaskState>() == STRICT_TS_INVALID); CHECK(json().get<StrictTaskState>() == STRICT_TS_INVALID);
// comparison of enum and json
CHECK(STRICT_TS_STOPPED == json("stopped"));
CHECK(STRICT_TS_RUNNING == json("running"));
CHECK(STRICT_TS_COMPLETED == json("completed"));
CHECK(STRICT_TS_INVALID == json());
// invalid json -> exception thrown // invalid json -> exception thrown
json _; json _;
CHECK_THROWS_WITH_AS(_ = json("what?").get<StrictTaskState>(), "[json.exception.out_of_range.410] enum value out of range for StrictTaskState: \"what?\"", json::out_of_range&); CHECK_THROWS_WITH_AS(_ = json("what?").get<StrictTaskState>(), "[json.exception.out_of_range.410] enum value out of range for StrictTaskState: \"what?\"", json::out_of_range&);
// conversion of unmapped enum -> exception thrown // conversion of unmapped enum -> exception thrown
CHECK_THROWS_WITH_AS(json(STRICT_TS_OTHER), "[json.exception.out_of_range.410] enum value out of range for StrictTaskState", json::out_of_range&); CHECK_THROWS_WITH_AS(json(STRICT_TS_OTHER), "[json.exception.out_of_range.410] enum value out of range for StrictTaskState", json::out_of_range&);
// comparing an unmapped enum with json throws the same exception
CHECK_THROWS_WITH_AS(static_cast<void>(STRICT_TS_OTHER < json("x")), "[json.exception.out_of_range.410] enum value out of range for StrictTaskState", json::out_of_range&);
} }
} }
+9
View File
@@ -54,6 +54,15 @@ static_assert(noexcept(json(pod {})), "");
static_assert(noexcept(std::declval<json>().get<pod>()), ""); static_assert(noexcept(std::declval<json>().get<pod>()), "");
static_assert(!noexcept(std::declval<json>().get<pod_bis>()), ""); static_assert(!noexcept(std::declval<json>().get<pod_bis>()), "");
static_assert(noexcept(json(pod{})), ""); static_assert(noexcept(json(pod{})), "");
// comparing with a scalar is noexcept exactly when converting the scalar is
static_assert(noexcept(std::declval<const json&>() == 1), "");
static_assert(noexcept(1 != std::declval<const json&>()), "");
static_assert(noexcept(std::declval<const json&>() < 2.5), "");
static_assert(noexcept(nullptr == std::declval<const json&>()), "");
static_assert(!noexcept(std::declval<const json&>() == "foo"), "");
static_assert(!noexcept("foo" >= std::declval<const json&>()), "");
static_assert(noexcept(std::declval<const json&>() == std::declval<const json&>()), "");
} // namespace } // namespace
TEST_CASE("noexcept") TEST_CASE("noexcept")