1
0
mirror of https://github.com/nlohmann/json.git synced 2025-07-28 12:02:00 +03:00

Reimplement value() access functions (#3663)

* Reimplement value() access functions

* Merges the 'const char *' with the 'ValueType &&' overloads.
* Fixes ambiguities when default value is 0.
* Fixes 'no matching function' error when specifying ValueType template
  parameter.
* Fixes incorrect template parameter order in previous overloads.

* Add additional value() tests

* Make JSON_MultipleHeaders visible to unit tests

Define the macro JSON_TEST_USING_MULTIPLE_HEADERS to 0/1 depending on
JSON_MultipleHeaders.

* Add type_traits unit test

* Update documentation
This commit is contained in:
Florian Albrechtskirchinger
2022-08-07 13:54:55 +02:00
committed by GitHub
parent 8eee62d388
commit 0c7a18374c
7 changed files with 694 additions and 127 deletions

View File

@ -2194,14 +2194,24 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
}
private:
template<typename KeyType>
using is_comparable_with_object_key = detail::is_comparable <
object_comparator_t, const typename object_t::key_type&, KeyType >;
template<typename ValueType>
using value_return_type = std::conditional <
detail::is_c_string_uncvref<ValueType>::value,
string_t, typename std::decay<ValueType>::type >;
public:
/// @brief access specified object element with default value
/// @sa https://json.nlohmann.me/api/basic_json/value/
// this is the value(const typename object_t::key_type&) overload
template < class KeyType, class ValueType, detail::enable_if_t <
std::is_same<KeyType, typename object_t::key_type>::value
template < class ValueType, detail::enable_if_t <
!detail::is_transparent<object_comparator_t>::value
&& detail::is_getable<basic_json_t, ValueType>::value
&& !std::is_same<value_t, ValueType>::value, int > = 0 >
typename std::decay<ValueType>::type value(const KeyType& key, ValueType && default_value) const
&& !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()))
@ -2210,7 +2220,32 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
const auto it = find(key);
if (it != end())
{
return it->template get<typename std::decay<ValueType>::type>();
return it->template get<ValueType>();
}
return default_value;
}
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
}
/// @brief access specified object element with default value
/// @sa https://json.nlohmann.me/api/basic_json/value/
template < class ValueType, class ReturnType = typename value_return_type<ValueType>::type,
detail::enable_if_t <
!detail::is_transparent<object_comparator_t>::value
&& detail::is_getable<basic_json_t, ReturnType>::value
&& !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 value and given default value otherwise
const auto it = find(key);
if (it != end())
{
return it->template get<ReturnType>();
}
return std::forward<ValueType>(default_value);
@ -2221,36 +2256,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief access specified object element with default value
/// @sa https://json.nlohmann.me/api/basic_json/value/
/// overload for a default value of type const char*
string_t value(const typename object_t::key_type& key, const char* default_value) const
{
return value(key, string_t(default_value));
}
// these two functions, in conjunction with value(const KeyType &, ValueType &&),
// resolve an ambiguity that would otherwise occur between the json_pointer and
// typename object_t::key_type & overloads
template < class ValueType, detail::enable_if_t <
detail::is_getable<basic_json_t, ValueType>::value
&& !std::is_same<value_t, ValueType>::value, int > = 0 >
typename std::decay<ValueType>::type value(const char* key, ValueType && default_value) const
{
return value(typename object_t::key_type(key), std::forward<ValueType>(default_value));
}
string_t value(const char* key, const char* default_value) const
{
return value(typename object_t::key_type(key), string_t(default_value));
}
/// @brief access specified object element with default value
/// @sa https://json.nlohmann.me/api/basic_json/value/
/// using std::is_convertible in a std::enable_if will fail when using explicit conversions
template < class KeyType, class ValueType, detail::enable_if_t <
detail::is_getable<basic_json_t, ValueType>::value
&& !std::is_same<value_t, ValueType>::value
&& detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int > = 0 >
typename std::decay<ValueType>::type value(KeyType && key, ValueType && default_value) const
template < class ValueType, class KeyType, detail::enable_if_t <
detail::is_transparent<object_comparator_t>::value
&& !detail::is_json_pointer<KeyType>::value
&& is_comparable_with_object_key<KeyType>::value
&& detail::is_getable<basic_json_t, ValueType>::value
&& !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()))
@ -2259,7 +2271,34 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
const auto it = find(std::forward<KeyType>(key));
if (it != end())
{
return it->template get<typename std::decay<ValueType>::type>();
return it->template get<ValueType>();
}
return default_value;
}
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
}
/// @brief access specified object element via JSON Pointer with default value
/// @sa https://json.nlohmann.me/api/basic_json/value/
template < class ValueType, class KeyType, class ReturnType = typename value_return_type<ValueType>::type,
detail::enable_if_t <
detail::is_transparent<object_comparator_t>::value
&& !detail::is_json_pointer<KeyType>::value
&& is_comparable_with_object_key<KeyType>::value
&& detail::is_getable<basic_json_t, ReturnType>::value
&& !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 value and given default value otherwise
const auto it = find(std::forward<KeyType>(key));
if (it != end())
{
return it->template get<ReturnType>();
}
return std::forward<ValueType>(default_value);
@ -2268,20 +2307,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
}
/// @brief access specified object element with default value
/// @sa https://json.nlohmann.me/api/basic_json/value/
/// overload for a default value of type const char*
template < class KeyType, detail::enable_if_t <
!detail::is_json_pointer<KeyType>::value, int > = 0 >
string_t value(KeyType && key, const char* default_value) const
{
return value(std::forward<KeyType>(key), string_t(default_value));
}
/// @brief access specified object element via JSON Pointer with default value
/// @sa https://json.nlohmann.me/api/basic_json/value/
template < class ValueType, detail::enable_if_t <
detail::is_getable<basic_json_t, ValueType>::value, int> = 0 >
detail::is_getable<basic_json_t, ValueType>::value
&& !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 objects
@ -2301,29 +2331,50 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
}
/// @brief access specified object element via JSON Pointer with default value
/// @sa https://json.nlohmann.me/api/basic_json/value/
template < class ValueType, class ReturnType = typename value_return_type<ValueType>::type,
detail::enable_if_t <
detail::is_getable<basic_json_t, ReturnType>::value
&& !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 objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
// if pointer resolves a value, return it or use default value
JSON_TRY
{
return ptr.get_checked(this).template get<ReturnType>();
}
JSON_INTERNAL_CATCH (out_of_range&)
{
return std::forward<ValueType>(default_value);
}
}
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
}
template < class ValueType, class BasicJsonType, detail::enable_if_t <
detail::is_getable<basic_json_t, ValueType>::value, int> = 0 >
detail::is_basic_json<BasicJsonType>::value
&& detail::is_getable<basic_json_t, ValueType>::value
&& !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
ValueType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, const ValueType& default_value) const
{
return value(ptr.convert(), default_value);
}
/// @brief access specified object element via JSON Pointer with default value
/// @sa https://json.nlohmann.me/api/basic_json/value/
/// overload for a default value of type const char*
JSON_HEDLEY_NON_NULL(3)
string_t value(const json_pointer& ptr, const char* default_value) const
{
return value(ptr, string_t(default_value));
}
template<typename BasicJsonType>
template < class ValueType, class BasicJsonType, class ReturnType = typename value_return_type<ValueType>::type,
detail::enable_if_t <
detail::is_basic_json<BasicJsonType>::value
&& detail::is_getable<basic_json_t, ReturnType>::value
&& !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
JSON_HEDLEY_NON_NULL(3)
string_t value(const typename ::nlohmann::json_pointer<BasicJsonType>& ptr, const char* default_value) const
ReturnType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, ValueType && default_value) const
{
return value(ptr.convert(), default_value);
return value(ptr.convert(), std::forward<ValueType>(default_value));
}
/// @brief access the first element