I have a class hierarchy that looks like this: class A is composed of classes B and C.
B and C each have a function that returns boost::json::object, which looks like this in case of B: {"B": "someValue"}
A is supposed to compose each of these objects into a structure like this:
{
"A": {
"B": "someValue",
"C": "someOtherValue"
}
}
The problem I'm facing is, that the resulting object always looks like this:
{
"A": [
{ "B": "someValue" },
{ "C": "someOtherValue" }
]
}
As you can see, the objects from the subclasses are not added as key-value pairs, but as objects, each containing a single pair, into an array.
Here's a snippet to reproduce the issue:
#include <iostream>
#include <boost/json.hpp>
using namespace boost::json;
object makeObject(std::string key, int value)
{
object obj;
obj[key] = value;
return obj;
}
int main() {
object obj;
obj["main"] = {makeObject("test1", 123), makeObject("test2", 456)};
std::cout << obj << std::endl;
return 0;
}
According to the Quick Look documentation of boost, I would have expected this to not create an array with single-value objects in it. What am I doing wrong here?
EDIT
I modified my example based on sehe's answer:
#include <iostream>
#include <boost/json.hpp>
auto makeProp(string_view name, value v)
{
return object::value_type(name, std::move(v));
}
int main() {
object obj;
obj["main"] = {makeProp("test1", 123), makeProp("test2", 456)};
std::cout << obj << std::endl;
return 0;
}
But this still generates undesired output, unless I made a mistake:
{"main":[["test1",123],["test2",456]]}
To elaborate further on my usecase for the helper function, I originally intended for this to be a quick writeup to recreate the issue I described with my class hierarchy above.
I made a longer program that shows the issue in a more understandable way hopefully:
#include <boost/json.hpp>
#include <iostream>
using namespace boost::json;
class B
{
public:
key_value_pair makeProp()
{
value v = {"property1", 1};
return object::value_type("B", std::move(v));
}
};
class C
{
public:
key_value_pair makeProp()
{
value v = {{"property1", 1}, {"property2", {1, 2, 3}}};
return object::value_type("C", std::move(v));
}
};
class A
{
public:
object makeProp()
{
B b;
C c;
object obj;
obj["A"] = {b.makeProp(), c.makeProp()};
return obj;
}
};
int main()
{
A a;
std::cout << a.makeProp() << std::endl;
return 0;
}
I hope this explains why I added the helper function, and makes it clearer what I want to achieve.
This returns:
{
"A": [
[
"B",
[
"property1",
1
]
],
[
"C",
{
"property1": 1,
"property2": [
1,
2,
3
]
}
]
]
}
While I would have expected:
{
"A": {
"B": {
"property1": 1
},
"C": {
"property1": 1,
"property2": [
1,
2,
3
]
}
}
}
CodePudding user response:
makeObject
returns single objects. You pass them as the initializer list to a json::value
, so you should expect {makeObject(...), makeObject(...)}
to create an array: docs
If the initializer list consists of key/value pairs, an object is created. Otherwise an array is created.
Instead, you want to make an initializer list of key-value pair, not objects:
#include <iostream>
#include <boost/json/src.hpp> // for COLIRU
namespace json = boost::json;
int main() {
// construct:
json::object obj{
{"main",
{
{"test1", 123},
{"test2", 456},
}},
};
std::cout << obj << std::endl;
// update:
obj["main"] = {{"B", "someValue"}, {"C", "someOtherValue"}};
std::cout << obj << std::endl;
}
See it Live On Coliru:
{"main":{"test1":123,"test2":456}}
{"main":{"B":"someValue","C":"someOtherValue"}}
BONUS
If you /need/ to have the helper function for some reason:
auto makeProp(std::string_view name, json::value v) {
return json::object::value_type(name, std::move(v));
}