Here's a couple suggestions that I think might be worth adding to improve the usage of value() function:
- Use "universal reference"
&& instead of const& for default_value to lift a problem that const ValueType& default_value inhibits move when default_value is temporary/r-value:
Before:
template<class ValueType, typename std::enable_if<
std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>
ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const
{
// at only works for objects
if (JSON_LIKELY(is_object()))
{
// if key is found, return value and given default value otherwise
const auto it = find(key);
if (it != end())
{
return *it;
}
return default_value;
}
JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name())));
}
After
template<class ValueType, typename std::enable_if<
std::is_convertible<basic_json_t, detail::uncvref_t<ValueType>>::value, int>::type = 0>
detail::uncvref_t<ValueType> value(const typename object_t::key_type& key, ValueType&& default_value) const &
{
// at only works for objects
if (JSON_LIKELY(is_object()))
{
// if key is found, return value and given default value otherwise
const auto it = find(key);
if (it != end())
{
return *it;
}
return std::forward<ValueType>(default_value);
}
JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name())));
}
This will allow this:
json j{{"x", "test"}};
std::string defval = "default value";
auto val = j.value("y", std::move(defval) /* or a temporary constructed in-place */);
// defval is now empty (moved-from) and val contains "default value"
- Provide r-value reference overload for
value() to allow moving from JSON's values when JSON is temporary/r-value:
template<class ValueType, typename std::enable_if<
std::is_convertible<basic_json_t, detail::uncvref_t<ValueType>>::value, int>::type = 0>
detail::uncvref_t<ValueType> value(const typename object_t::key_type& key, ValueType&& default_value) &&
{
// at only works for objects
if (JSON_LIKELY(is_object()))
{
// if key is found, return value and given default value otherwise
const auto it = find(key);
if (it != end())
{
return std::move(it->template get_ref<ValueType&>());
}
return std::forward<ValueType>(default_value);
}
JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name())));
}
This will make possible the following:
json j{{"x", "123"}};
auto val = std::move(j).value("x", std::string{"whatever"});
// j["x"] in now empty (moved-from) and val contains "123"
Here's a couple suggestions that I think might be worth adding to improve the usage of value() function:
&&instead ofconst&fordefault_valueto lift a problem thatconst ValueType& default_valueinhibits move whendefault_valueis temporary/r-value:Before:
After
This will allow this:
json j{{"x", "test"}}; std::string defval = "default value"; auto val = j.value("y", std::move(defval) /* or a temporary constructed in-place */); // defval is now empty (moved-from) and val contains "default value"value()to allow moving from JSON's values when JSON is temporary/r-value:This will make possible the following:
json j{{"x", "123"}}; auto val = std::move(j).value("x", std::string{"whatever"}); // j["x"] in now empty (moved-from) and val contains "123"