Deduplicate the lookup/default/throw body of value()

The six non-deprecated value() overloads each held a full copy of the
same body: the four key-based overloads looked up the key and either
returned the found element converted to the requested type or the
default value (throwing type_error.306 if this is not an object), and
the two json_pointer overloads did the same via
ptr.get_checked_or_null(), throwing type_error.306 unless
is_structured(). Replace the duplicated bodies with two private
helpers, value_member() and value_pointee(), that return a
const basic_json* (null when not found) and do the type check/throw
once each. Every value() overload now just picks between the found
pointer's get<T>() and the default.

Same signatures, template parameters, SFINAE conditions, exception id,
message and this context on every overload.

Overlaps #5689 (routes find() through lookup_key()) and #5705 (adds a
deleted integral-key value() next to these overloads); whichever of
this commit and those PRs lands second will need a small rebase.

#5724 item 4

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann
2026-09-30 19:05:03 +02:00
parent a0e01e3b9c
commit 03d53596f9
2 changed files with 100 additions and 172 deletions
+50 -86
View File
@@ -2958,6 +2958,36 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
detail::is_c_string_uncvref<ValueType>::value,
string_t, typename std::decay<ValueType>::type >;
/// @brief look up @a key for value(), the single place shared by all key-based overloads
/// @throw type_error.306 if this is not an object
/// @return a pointer to the found value, or `nullptr` if @a key was not found
template<typename KeyType>
const basic_json* value_member(KeyType&& key) const
{
// value only works for objects
if (JSON_HEDLEY_UNLIKELY(!is_object()))
{
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
}
const auto it = find(std::forward<KeyType>(key));
return it != end() ? &*it : nullptr;
}
/// @brief resolve @a ptr for value(), the single place shared by both json_pointer overloads
/// @throw type_error.306 if this is not an array or object
/// @return a pointer to the resolved value, or `nullptr` if @a ptr does not resolve
const basic_json* value_pointee(const json_pointer& ptr) const
{
// value only works for arrays and objects
if (JSON_HEDLEY_UNLIKELY(!is_structured()))
{
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
}
return ptr.get_checked_or_null(this);
}
public:
/// @brief access specified object element with default value
/// @sa https://json.nlohmann.me/api/basic_json/value/
@@ -2967,20 +2997,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
&& !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const
{
// value only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
// If 'key' is found, return its value. Otherwise, return `default_value'.
const auto it = find(key);
if (it != end())
{
return it->template get<ValueType>();
}
return default_value;
}
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
// If 'key' is found, return its value. Otherwise, return `default_value'.
const auto* found = value_member(key);
return found != nullptr ? found->template get<ValueType>() : default_value;
}
/// @brief access specified object element with default value
@@ -2992,20 +3011,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
&& !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
ReturnType value(const typename object_t::key_type& key, ValueType && default_value) const
{
// value only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
// If 'key' is found, return its value. Otherwise, return `default_value'.
const auto it = find(key);
if (it != end())
{
return it->template get<ReturnType>();
}
return std::forward<ValueType>(default_value);
}
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
// If 'key' is found, return its value. Otherwise, return `default_value'.
const auto* found = value_member(key);
return found != nullptr ? found->template get<ReturnType>() : std::forward<ValueType>(default_value);
}
/// @brief access specified object element with default value
@@ -3018,20 +3026,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
&& !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
ValueType value(KeyType && key, const ValueType& default_value) const
{
// value only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
// If 'key' is found, return its value. Otherwise, return `default_value'.
const auto it = find(std::forward<KeyType>(key));
if (it != end())
{
return it->template get<ValueType>();
}
return default_value;
}
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
// If 'key' is found, return its value. Otherwise, return `default_value'.
const auto* found = value_member(std::forward<KeyType>(key));
return found != nullptr ? found->template get<ValueType>() : default_value;
}
/// @brief access specified object element with default value
@@ -3045,20 +3042,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
&& !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
ReturnType value(KeyType && key, ValueType && default_value) const
{
// value only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
// If 'key' is found, return its value. Otherwise, return `default_value'.
const auto it = find(std::forward<KeyType>(key));
if (it != end())
{
return it->template get<ReturnType>();
}
return std::forward<ValueType>(default_value);
}
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
// If 'key' is found, return its value. Otherwise, return `default_value'.
const auto* found = value_member(std::forward<KeyType>(key));
return found != nullptr ? found->template get<ReturnType>() : std::forward<ValueType>(default_value);
}
/// @brief access specified object element via JSON Pointer with default value
@@ -3068,21 +3054,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
&& !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
ValueType value(const json_pointer& ptr, const ValueType& default_value) const
{
// value only works for arrays and objects
if (JSON_HEDLEY_LIKELY(is_structured()))
{
// If the pointer resolves to a value, return it. Otherwise, return
// 'default_value'.
const auto* res = ptr.get_checked_or_null(this);
if (JSON_HEDLEY_LIKELY(res != nullptr))
{
return res->template get<ValueType>();
}
return default_value;
}
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
// If the pointer resolves to a value, return it. Otherwise, return
// 'default_value'.
const auto* found = value_pointee(ptr);
return found != nullptr ? found->template get<ValueType>() : default_value;
}
/// @brief access specified object element via JSON Pointer with default value
@@ -3093,21 +3068,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
&& !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
ReturnType value(const json_pointer& ptr, ValueType && default_value) const
{
// value only works for arrays and objects
if (JSON_HEDLEY_LIKELY(is_structured()))
{
// If the pointer resolves to a value, return it. Otherwise, return
// 'default_value'.
const auto* res = ptr.get_checked_or_null(this);
if (JSON_HEDLEY_LIKELY(res != nullptr))
{
return res->template get<ReturnType>();
}
return std::forward<ValueType>(default_value);
}
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
// If the pointer resolves to a value, return it. Otherwise, return
// 'default_value'.
const auto* found = value_pointee(ptr);
return found != nullptr ? found->template get<ReturnType>() : std::forward<ValueType>(default_value);
}
template < class ValueType, class BasicJsonType, detail::enable_if_t <
+50 -86
View File
@@ -29038,6 +29038,36 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
detail::is_c_string_uncvref<ValueType>::value,
string_t, typename std::decay<ValueType>::type >;
/// @brief look up @a key for value(), the single place shared by all key-based overloads
/// @throw type_error.306 if this is not an object
/// @return a pointer to the found value, or `nullptr` if @a key was not found
template<typename KeyType>
const basic_json* value_member(KeyType&& key) const
{
// value only works for objects
if (JSON_HEDLEY_UNLIKELY(!is_object()))
{
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
}
const auto it = find(std::forward<KeyType>(key));
return it != end() ? &*it : nullptr;
}
/// @brief resolve @a ptr for value(), the single place shared by both json_pointer overloads
/// @throw type_error.306 if this is not an array or object
/// @return a pointer to the resolved value, or `nullptr` if @a ptr does not resolve
const basic_json* value_pointee(const json_pointer& ptr) const
{
// value only works for arrays and objects
if (JSON_HEDLEY_UNLIKELY(!is_structured()))
{
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
}
return ptr.get_checked_or_null(this);
}
public:
/// @brief access specified object element with default value
/// @sa https://json.nlohmann.me/api/basic_json/value/
@@ -29047,20 +29077,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
&& !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const
{
// value only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
// If 'key' is found, return its value. Otherwise, return `default_value'.
const auto it = find(key);
if (it != end())
{
return it->template get<ValueType>();
}
return default_value;
}
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
// If 'key' is found, return its value. Otherwise, return `default_value'.
const auto* found = value_member(key);
return found != nullptr ? found->template get<ValueType>() : default_value;
}
/// @brief access specified object element with default value
@@ -29072,20 +29091,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
&& !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
ReturnType value(const typename object_t::key_type& key, ValueType && default_value) const
{
// value only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
// If 'key' is found, return its value. Otherwise, return `default_value'.
const auto it = find(key);
if (it != end())
{
return it->template get<ReturnType>();
}
return std::forward<ValueType>(default_value);
}
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
// If 'key' is found, return its value. Otherwise, return `default_value'.
const auto* found = value_member(key);
return found != nullptr ? found->template get<ReturnType>() : std::forward<ValueType>(default_value);
}
/// @brief access specified object element with default value
@@ -29098,20 +29106,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
&& !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
ValueType value(KeyType && key, const ValueType& default_value) const
{
// value only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
// If 'key' is found, return its value. Otherwise, return `default_value'.
const auto it = find(std::forward<KeyType>(key));
if (it != end())
{
return it->template get<ValueType>();
}
return default_value;
}
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
// If 'key' is found, return its value. Otherwise, return `default_value'.
const auto* found = value_member(std::forward<KeyType>(key));
return found != nullptr ? found->template get<ValueType>() : default_value;
}
/// @brief access specified object element with default value
@@ -29125,20 +29122,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
&& !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
ReturnType value(KeyType && key, ValueType && default_value) const
{
// value only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
// If 'key' is found, return its value. Otherwise, return `default_value'.
const auto it = find(std::forward<KeyType>(key));
if (it != end())
{
return it->template get<ReturnType>();
}
return std::forward<ValueType>(default_value);
}
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
// If 'key' is found, return its value. Otherwise, return `default_value'.
const auto* found = value_member(std::forward<KeyType>(key));
return found != nullptr ? found->template get<ReturnType>() : std::forward<ValueType>(default_value);
}
/// @brief access specified object element via JSON Pointer with default value
@@ -29148,21 +29134,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
&& !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
ValueType value(const json_pointer& ptr, const ValueType& default_value) const
{
// value only works for arrays and objects
if (JSON_HEDLEY_LIKELY(is_structured()))
{
// If the pointer resolves to a value, return it. Otherwise, return
// 'default_value'.
const auto* res = ptr.get_checked_or_null(this);
if (JSON_HEDLEY_LIKELY(res != nullptr))
{
return res->template get<ValueType>();
}
return default_value;
}
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
// If the pointer resolves to a value, return it. Otherwise, return
// 'default_value'.
const auto* found = value_pointee(ptr);
return found != nullptr ? found->template get<ValueType>() : default_value;
}
/// @brief access specified object element via JSON Pointer with default value
@@ -29173,21 +29148,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
&& !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
ReturnType value(const json_pointer& ptr, ValueType && default_value) const
{
// value only works for arrays and objects
if (JSON_HEDLEY_LIKELY(is_structured()))
{
// If the pointer resolves to a value, return it. Otherwise, return
// 'default_value'.
const auto* res = ptr.get_checked_or_null(this);
if (JSON_HEDLEY_LIKELY(res != nullptr))
{
return res->template get<ReturnType>();
}
return std::forward<ValueType>(default_value);
}
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
// If the pointer resolves to a value, return it. Otherwise, return
// 'default_value'.
const auto* found = value_pointee(ptr);
return found != nullptr ? found->template get<ReturnType>() : std::forward<ValueType>(default_value);
}
template < class ValueType, class BasicJsonType, detail::enable_if_t <