working on #235
This commit is contained in:
parent
fadf286653
commit
9ecf83f630
6 changed files with 210 additions and 2 deletions
26
doc/examples/push_back__initializer_list.cpp
Normal file
26
doc/examples/push_back__initializer_list.cpp
Normal file
|
@ -0,0 +1,26 @@
|
|||
#include <json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
int main()
|
||||
{
|
||||
// create JSON values
|
||||
json object = {{"one", 1}, {"two", 2}};
|
||||
json null;
|
||||
|
||||
// print values
|
||||
std::cout << object << '\n';
|
||||
std::cout << null << '\n';
|
||||
|
||||
// add values:
|
||||
object.push_back({"three", 3}); // object is extended
|
||||
object += {"four", 4}; // object is extended
|
||||
null.push_back({"five", 5}); // null is converted to array
|
||||
|
||||
// print values
|
||||
std::cout << object << '\n';
|
||||
std::cout << null << '\n';
|
||||
|
||||
// would throw:
|
||||
//object.push_back({1, 2, 3});
|
||||
}
|
1
doc/examples/push_back__initializer_list.link
Normal file
1
doc/examples/push_back__initializer_list.link
Normal file
|
@ -0,0 +1 @@
|
|||
<a target="_blank" href="http://melpon.org/wandbox/permlink/wZF4dRHjfCyjb3rx"><b>online</b></a>
|
4
doc/examples/push_back__initializer_list.output
Normal file
4
doc/examples/push_back__initializer_list.output
Normal file
|
@ -0,0 +1,4 @@
|
|||
{"one":1,"two":2}
|
||||
null
|
||||
{"four":4,"one":1,"three":3,"two":2}
|
||||
[["five",5]]
|
50
src/json.hpp
50
src/json.hpp
|
@ -4878,7 +4878,55 @@ class basic_json
|
|||
reference operator+=(const typename object_t::value_type& val)
|
||||
{
|
||||
push_back(val);
|
||||
return operator[](val.first);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief add an object to an object
|
||||
|
||||
This function allows to use `push_back` with an initializer list. In case
|
||||
|
||||
1. the current value is an object,
|
||||
2. the initializer list @a init contains only two elements, and
|
||||
3. the first element of @a init is a string,
|
||||
|
||||
@a init is converted into an object element and added using
|
||||
@ref push_back(const typename object_t::value_type&). Otherwise, @a init
|
||||
is converted to a JSON value and added using @ref push_back(basic_json&&).
|
||||
|
||||
@param init an initializer list
|
||||
|
||||
@complexity Linear in the size of the initializer list @a init.
|
||||
|
||||
@note This function is required to resolve an ambiguous overload error,
|
||||
because pairs like `{"key", "value"}` can be both interpreted as
|
||||
`object_t::value_type` or `std::initializer_list<basic_json>`, see
|
||||
https://github.com/nlohmann/json/issues/235 for more information.
|
||||
|
||||
@liveexample{The example shows how initializer lists are treated as
|
||||
objects when possible.,push_back__initializer_list}
|
||||
*/
|
||||
void push_back(std::initializer_list<basic_json> init)
|
||||
{
|
||||
if (is_object() and init.size() == 2 and init.begin()->is_string())
|
||||
{
|
||||
const string_t key = *init.begin();
|
||||
push_back(typename object_t::value_type(key, *(init.begin() + 1)));
|
||||
}
|
||||
else
|
||||
{
|
||||
push_back(basic_json(init));
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief add an object to an object
|
||||
@copydoc push_back(std::initializer_list<basic_json>)
|
||||
*/
|
||||
reference operator+=(std::initializer_list<basic_json> init)
|
||||
{
|
||||
push_back(init);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
@ -4878,7 +4878,55 @@ class basic_json
|
|||
reference operator+=(const typename object_t::value_type& val)
|
||||
{
|
||||
push_back(val);
|
||||
return operator[](val.first);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief add an object to an object
|
||||
|
||||
This function allows to use `push_back` with an initializer list. In case
|
||||
|
||||
1. the current value is an object,
|
||||
2. the initializer list @a init contains only two elements, and
|
||||
3. the first element of @a init is a string,
|
||||
|
||||
@a init is converted into an object element and added using
|
||||
@ref push_back(const typename object_t::value_type&). Otherwise, @a init
|
||||
is converted to a JSON value and added using @ref push_back(basic_json&&).
|
||||
|
||||
@param init an initializer list
|
||||
|
||||
@complexity Linear in the size of the initializer list @a init.
|
||||
|
||||
@note This function is required to resolve an ambiguous overload error,
|
||||
because pairs like `{"key", "value"}` can be both interpreted as
|
||||
`object_t::value_type` or `std::initializer_list<basic_json>`, see
|
||||
https://github.com/nlohmann/json/issues/235 for more information.
|
||||
|
||||
@liveexample{The example shows how initializer lists are treated as
|
||||
objects when possible.,push_back__initializer_list}
|
||||
*/
|
||||
void push_back(std::initializer_list<basic_json> init)
|
||||
{
|
||||
if (is_object() and init.size() == 2 and init.begin()->is_string())
|
||||
{
|
||||
const string_t key = *init.begin();
|
||||
push_back(typename object_t::value_type(key, *(init.begin() + 1)));
|
||||
}
|
||||
else
|
||||
{
|
||||
push_back(basic_json(init));
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief add an object to an object
|
||||
@copydoc push_back(std::initializer_list<basic_json>)
|
||||
*/
|
||||
reference operator+=(std::initializer_list<basic_json> init)
|
||||
{
|
||||
push_back(init);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
@ -7920,6 +7920,42 @@ TEST_CASE("modifiers")
|
|||
"cannot use push_back() with number");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("with initializer_list")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j;
|
||||
j.push_back({"foo", "bar"});
|
||||
CHECK(j == json::array({{"foo", "bar"}}));
|
||||
|
||||
json k;
|
||||
k.push_back({1, 2, 3});
|
||||
CHECK(k == json::array({{1, 2, 3}}));
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j = {1, 2, 3};
|
||||
j.push_back({"foo", "bar"});
|
||||
CHECK(j == json({1, 2, 3, {"foo", "bar"}}));
|
||||
|
||||
json k = {1, 2, 3};
|
||||
k.push_back({1, 2, 3});
|
||||
CHECK(k == json({1, 2, 3, {1, 2, 3}}));
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j = {{"key1", 1}};
|
||||
j.push_back({"key2", "bar"});
|
||||
CHECK(j == json({{"key1", 1}, {"key2", "bar"}}));
|
||||
|
||||
json k = {{"key1", 1}};
|
||||
CHECK_THROWS_AS(k.push_back({1, 2, 3, 4}), std::domain_error);
|
||||
CHECK_THROWS_WITH(k.push_back({1, 2, 3, 4}), "cannot use push_back() with object");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("operator+=")
|
||||
|
@ -8016,6 +8052,42 @@ TEST_CASE("modifiers")
|
|||
"cannot use push_back() with number");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("with initializer_list")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j;
|
||||
j += {"foo", "bar"};
|
||||
CHECK(j == json::array({{"foo", "bar"}}));
|
||||
|
||||
json k;
|
||||
k += {1, 2, 3};
|
||||
CHECK(k == json::array({{1, 2, 3}}));
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j = {1, 2, 3};
|
||||
j += {"foo", "bar"};
|
||||
CHECK(j == json({1, 2, 3, {"foo", "bar"}}));
|
||||
|
||||
json k = {1, 2, 3};
|
||||
k += {1, 2, 3};
|
||||
CHECK(k == json({1, 2, 3, {1, 2, 3}}));
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j = {{"key1", 1}};
|
||||
j += {"key2", "bar"};
|
||||
CHECK(j == json({{"key1", 1}, {"key2", "bar"}}));
|
||||
|
||||
json k = {{"key1", 1}};
|
||||
CHECK_THROWS_AS((k += {1, 2, 3, 4}), std::domain_error);
|
||||
CHECK_THROWS_WITH((k += {1, 2, 3, 4}), "cannot use push_back() with object");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("insert")
|
||||
|
@ -13992,6 +14064,15 @@ TEST_CASE("regression tests")
|
|||
|
||||
CHECK(dest == expected);
|
||||
}
|
||||
|
||||
SECTION("issue ##235 - ambiguous overload for 'push_back' and 'operator+='")
|
||||
{
|
||||
json data = {{"key", "value"}};
|
||||
data.push_back({"key2", "value2"});
|
||||
data += {"key3", "value3"};
|
||||
|
||||
CHECK(data == json({{"key", "value"}, {"key2", "value2"}, {"key3", "value3"}}));
|
||||
}
|
||||
}
|
||||
|
||||
// special test case to check if memory is leaked if constructor throws
|
||||
|
|
Loading…
Reference in a new issue