In the below example I parse a json object using boost::json
.
When I print the type of the returned boost::json::value
it is of type object
, as expected.
I then have 2 classes which are identical in every way, other than in BraceInit
I initialise my member boost::json::value
using brace initialisation and in ParenInit
I initialise my member boost::json::value
using parens.
Using brace initialisation causes my object
to be converted into an array
, of size 1, containing my original object
.
#include <iostream>
#include <boost/json.hpp>
namespace json = boost::json;
void print_type(const json::value& jv)
{
switch (jv.kind())
{
case json::kind::object: std::cout << "object\n"; break;
case json::kind::array: std::cout << "array\n"; break;
default: std::cout << "other\n"; break;
}
};
struct BraceInit
{
BraceInit(json::value jv)
: _jv{jv}
{
print_type(_jv);
}
json::value _jv;
};
struct ParenInit
{
ParenInit(json::value jv)
: _jv(jv)
{
print_type(_jv);
}
json::value _jv;
};
int main()
{
const std::string str = R"({ "foo": "bar" })";
const json::value jv = json::parse(str);
print_type(jv);
BraceInit b(jv);
ParenInit p(jv);
return 0;
}
Output:
object array object
What is happening here?
Is my "brace initialisation" actually not doing brace initialisation as I expect, but rather creating an std::initializer_list
of size 1?
CodePudding user response:
From [class.base.init]/7
The expression-list or braced-init-list in a mem-initializer is used to initialize the designated subobject (or, in the case of a delegating constructor, the complete class object) according to the initialization rules of 11.6 for direct-initialization.
11.6 here refers to [dcl.init]
, which, under paragraph 17 states:
The semantics of initializers are as follows. The destination type is the type of the object or reference being initialized and the source type is the type of the initializer expression. If the initializer is not a single (possibly parenthesized) expression, the source type is not defined.
(17.1) — If the initializer is a (non-parenthesized) braced-init-list or is = braced-init-list, the object or reference is list-initialized (11.6.4).
11.6.4 simply refers to [dcl.init.list]
.
So, to me, it sounds like _jv{jv}
calls the initialization-list version of the constructor (if it exists), which, according to the boost documentation, produces an array.
Note: all items from C 17 draft N4659
You can see this in a simplified version here: https://godbolt.org/z/9qrf3EooY
Edit: cppreference simplifies this to:
A std::initializer_list object is automatically constructed when:
a braced-init-list is used to list-initialize an object, where the corresponding constructor accepts an std::initializer_list parameter