mirror of
https://github.com/nlohmann/json.git
synced 2026-07-09 12:05:10 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 13242f76cc | |||
| ae2182cce1 | |||
| 035c58fc5e | |||
| b03bec327a | |||
| acca7575ce | |||
| 2f383b80ee |
@@ -66,6 +66,24 @@ which forces the explicit `get` form and can catch unintended conversions at com
|
|||||||
floating-point value as an integer truncates it, and narrowing conversions may overflow. See
|
floating-point value as an integer truncates it, and narrowing conversions may overflow. See
|
||||||
[number conversion](types/number_handling.md#number-conversion) for details and how to guard against it.
|
[number conversion](types/number_handling.md#number-conversion) for details and how to guard against it.
|
||||||
|
|
||||||
|
!!! warning "std::optional direct construction from JSON null throws"
|
||||||
|
|
||||||
|
Constructing or assigning `std::optional<T>` directly from a JSON value does not correctly produce
|
||||||
|
`std::nullopt` for a JSON `null`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
json j_null;
|
||||||
|
std::optional<std::string> opt = j_null; // ❌ throws type_error 302
|
||||||
|
```
|
||||||
|
|
||||||
|
This is due to C++ language rules: `std::optional<T>` has its own converting constructor that is chosen over
|
||||||
|
`basic_json::operator T()` when both are viable. Use `get<std::optional<T>>()` or `get_to()` instead:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto opt = j_null.get<std::optional<std::string>>(); // ✅ std::nullopt
|
||||||
|
j_null.get_to(opt); // ✅ std::nullopt
|
||||||
|
```
|
||||||
|
|
||||||
## Putting values in
|
## Putting values in
|
||||||
|
|
||||||
The reverse direction works the same way: assigning or constructing a `json` from a C++ value converts it to JSON.
|
The reverse direction works the same way: assigning or constructing a `json` from a C++ value converts it to JSON.
|
||||||
|
|||||||
@@ -1761,16 +1761,27 @@ TEST_CASE("std::filesystem::path")
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !JSON_USE_IMPLICIT_CONVERSIONS
|
|
||||||
TEST_CASE("std::optional")
|
TEST_CASE("std::optional")
|
||||||
{
|
{
|
||||||
SECTION("null")
|
SECTION("null")
|
||||||
{
|
{
|
||||||
json j_null;
|
const json j_null;
|
||||||
std::optional<std::string> opt_null;
|
const std::optional<std::string> opt_null;
|
||||||
|
|
||||||
CHECK(json(opt_null) == j_null);
|
CHECK(json(opt_null) == j_null);
|
||||||
CHECK(j_null.get<std::optional<std::string>>() == std::nullopt);
|
CHECK(j_null.get<std::optional<std::string>>() == std::nullopt);
|
||||||
|
|
||||||
|
// Constructing std::optional<T> directly from JSON null throws because
|
||||||
|
// std::optional's own converting constructor is chosen over basic_json's
|
||||||
|
// operator T(). This is a language-level limitation (std::optional<T> is
|
||||||
|
// constructible from T, and T is constructible from basic_json via the
|
||||||
|
// operator); there is no SFINAE path that distinguishes "call from inside
|
||||||
|
// std::optional's constructor" from "direct call". Use get<std::optional<T>>()
|
||||||
|
// or get_to() instead for correct null handling. See #4864 and #5246.
|
||||||
|
CHECK_THROWS_WITH_AS(std::optional<std::string>(j_null),
|
||||||
|
"[json.exception.type_error.302] type must be string, but is null", json::type_error&);
|
||||||
|
CHECK_THROWS_WITH_AS(std::optional<int>(j_null),
|
||||||
|
"[json.exception.type_error.302] type must be number, but is null", json::type_error&);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("string")
|
SECTION("string")
|
||||||
@@ -1819,7 +1830,6 @@ TEST_CASE("std::optional")
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef JSON_HAS_CPP_17
|
#ifdef JSON_HAS_CPP_17
|
||||||
#undef JSON_HAS_CPP_17
|
#undef JSON_HAS_CPP_17
|
||||||
|
|||||||
Reference in New Issue
Block a user