I want an object obj to be initialized from an initializer_list of pairs. However, the second value of the pair is a variant of bool, int and again the obj. gcc reports trouble finding the right constructors I guess. Can I make this work recursively for the following code?
#include <utility>
#include <string>
#include <variant>
struct obj;
using val = std::variant<int, bool, obj>;
struct obj
{
obj(std::initializer_list<std::pair<std::string, val>> init) {
}
};
int main()
{
obj O = { {"level1_1", true }, { "level1_2", 1 }, { {"level2_1", 2}, {"level2_2", true}}};
}
gcc 12.1 doesn't get it:
<source>: In function 'int main()':
<source>:57:93: error: could not convert '{{"level1_1", true}, {"level1_2", 1}, {{"level2_1", 2}, {"level2_2", true}}}' from '<brace-enclosed initializer list>' to 'obj'
57 | obj O = { {"level1_1", true }, { "level1_2", 1 }, { {"level2_1", 2}, {"level2_2", true}}};
| ^
| |
|
Any hints on what I need to change?
EDIT: It seems that the approach using initializer lists is probably not suitable. Maybe there exists a solution using templates which is also appreciated. I know it is possible from nlohmanns json library (see section "JSON as first-class data type"). Also the solution should get by without using heap allocations during the initialization process.
As Igor noted, without any changes to your type or constructor, your code can compile fine with an explicit type specified for your subobject:
I believe the problem may originate with the particular combination of
std::pair, along with a variant that contains an incomplete type. We can observe this by replacingstd::pair<...>with our own custom type that lacks any internal storage:With this, we get your desired syntax, but lack any implementation. My guess here is that the problem lies with
std::pairin combination withstd::variant. We can get back our storage by havingkv_pairinstead be a convenience wrapper over pairs of strings and pointers, i.e.So for a full and complete implementation: