Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Aggregate initialization with nested map doesn't work expectedly

It seems I was a bit fuzzy when posing this question since it have been a few days that I’m trying to fix this problem and couldn’t reproduce it as an MRE probably the issue is somewhere else in my code. I am sorry for the time and effort of those who tried to answer this.


I want to store information about a graphql query so I need to store
the selections for each field, this requires using a nested map.

This is my how I tried to implement this however this won’t compile for nested
fields.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

struct NestedContainer;
struct NestedContainer {
  std::map<std::string, NestedContainer *> selections = std::map<std::string, NestedContainer *> ();
};

int main() {
  auto a = NestedContainer({
    {
      {
        "level1",
        {
          {
            {
              "level2",
              {}
            }
          }
        }
      }
    }
  });
  return 0;
}

clang output

<source>:15:13: error: no matching constructor for initialization of 'std::map<std::string, NestedContainer *>' (aka 'map<basic_string<char>, NestedContainer *>')
            {
            ^
/opt/compiler-explorer/gcc-12.2.0/lib/gcc/x86_64-linux-gnu/12.2.0/../../../../include/c++/12.2.0/bits/stl_map.h:204:7: note: candidate constructor not viable: cannot convert initializer list argument to 'const std::less<std::basic_string<char>>'
      map(const _Compare& __comp,
      ^
/opt/compiler-explorer/gcc-12.2.0/lib/gcc/x86_64-linux-gnu/12.2.0/../../../../include/c++/12.2.0/bits/stl_map.h:217:7: note: candidate constructor not viable: cannot convert initializer list argument to 'const map<basic_string<char>, NestedContainer *>'
      map(const map&) = default;
      ^
/opt/compiler-explorer/gcc-12.2.0/lib/gcc/x86_64-linux-gnu/12.2.0/../../../../include/c++/12.2.0/bits/stl_map.h:225:7: note: candidate constructor not viable: cannot convert initializer list argument to 'map<basic_string<char>, NestedContainer *>'
      map(map&&) = default;

gcc

<source>: In function 'int main()':
<source>:25:5: error: could not convert '{{{"level1", {{{"level2", <brace-enclosed initializer list>()}}}}}}' from '<brace-enclosed initializer list>' to 'std::map<std::__cxx11::basic_string<char>, NestedContainer*>'
   25 |     );
      |     ^
      |     |
      |     <brace-enclosed initializer list>
ASM generation compiler returned: 1
<source>: In function 'int main()':
<source>:25:5: error: could not convert '{{{"level1", {{{"level2", <brace-enclosed initializer list>()}}}}}}' from '<brace-enclosed initializer list>' to 'std::map<std::__cxx11::basic_string<char>, NestedContainer*>'
   25 |     );
      |     ^
      |     |
      |     <brace-enclosed initializer list>
Execution build compiler returned: 1

msvc

example.cpp
<source>(14): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'NestedContainer'
<source>(14): note: No constructor could take the source type, or constructor overload resolution was ambiguous
cl : Command line warning D9002 : ignoring unknown option '-std=c++20'
Compiler returned: 2

godbolt link

For those who ask why I use a pointer, not using a pointer fails as well.

struct NestedContainer {
  std::map<std::string, NestedContainer> selections = std::map<std::string, NestedContainer *> ();
};

int main() {
  auto a = NestedContainer({
    {
      {
        "level1",
        {
          {
            {
              "level2",
              {}
            }
          }
        }
      }
    }
  });
  return 0;
}

msvc

<source>:8:55: error: no viable conversion from 'map<[...], NestedContainer *>' to 'map<[...], NestedContainer>'
  std::map<std::string, NestedContainer> selections = std::map<std::string, NestedContainer *> ();
                                                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-12.2.0/lib/gcc/x86_64-linux-gnu/12.2.0/../../../../include/c++/12.2.0/bits/stl_map.h:217:7: note: candidate constructor not viable: no known conversion from 'std::map<std::string, NestedContainer *>' (aka 'map<basic_string<char>, NestedContainer *>') to 'const map<basic_string<char>, NestedContainer> &' for 1st argument
      map(const map&) = default;
      ^
/opt/compiler-explorer/gcc-12.2.0/lib/gcc/x86_64-linux-gnu/12.2.0/../../../../include/c++/12.2.0/bits/stl_map.h:225:7: note: candidate constructor not viable: no known conversion from 'std::map<std::string, NestedContainer *>' (aka 'map<basic_string<char>, NestedContainer *>') to 'map<basic_string<char>, NestedContainer> &&' for 1st argument
      map(map&&) = default;
      ^
/opt/compiler-explorer/gcc-12.2.0/lib/gcc/x86_64-linux-gnu/12.2.0/../../../../include/c++/12.2.0/bits/stl_map.h:238:7: note: candidate constructor not viable: no known conversion from 'std::map<std::string, NestedContainer *>' (aka 'map<basic_string<char>, NestedContainer *>') to 'initializer_list<value_type>' (aka 'initializer_list<pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char>>, NestedContainer>>') for 1st argument
      map(initializer_list<value_type> __l,
      ^
/opt/compiler-explorer/gcc-12.2.0/lib/gcc/x86_64-linux-gnu/12.2.0/../../../../include/c++/12.2.0/bits/stl_map.h:204:7: note: explicit constructor is not a candidate
      map(const _Compare& __comp,
      ^
/opt/compiler-explorer/gcc-12.2.0/lib/gcc/x86_64-linux-gnu/12.2.0/../../../../include/c++/12.2.0/bits/stl_map.h:246:7: note: explicit constructor is not a candidate
      map(const allocator_type& __a)

gcc

<source>:8:60: error: could not convert 'std::map<std::__cxx11::basic_string<char>, NestedContainer*>()' from 'map<[...],NestedContainer*>' to 'map<[...],NestedContainer>'
    8 |   std::map<std::string, NestedContainer> selections = std::map<std::string, NestedContainer *> ();
      |                                                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                                                            |
      |                                                            map<[...],NestedContainer*>
<source>: In function 'int main()':
<source>:26:4: error: could not convert '{{{"level1", {{{"level2", <brace-enclosed initializer list>()}}}}}}' from '<brace-enclosed initializer list>' to 'std::map<std::__cxx11::basic_string<char>, NestedContainer>'
   26 |   });
      |    ^
      |    |
      |    <brace-enclosed initializer list>
ASM generation compiler returned: 1
<source>:8:60: error: could not convert 'std::map<std::__cxx11::basic_string<char>, NestedContainer*>()' from 'map<[...],NestedContainer*>' to 'map<[...],NestedContainer>'
    8 |   std::map<std::string, NestedContainer> selections = std::map<std::string, NestedContainer *> ();
      |                                                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                                                            |
      |                                                            map<[...],NestedContainer*>
<source>: In function 'int main()':
<source>:26:4: error: could not convert '{{{"level1", {{{"level2", <brace-enclosed initializer list>()}}}}}}' from '<brace-enclosed initializer list>' to 'std::map<std::__cxx11::basic_string<char>, NestedContainer>'
   26 |   });
      |    ^
      |    |
      |    <brace-enclosed initializer list>
Execution build compiler returned: 1

msvc

example.cpp
/opt/compiler-explorer/windows/19.00.24210/include/xlocale(341): warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc
<source>(8): error C2664: 'std::map<std::string,NestedContainer,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>>::map(const std::map<_Kty,_Ty,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>> &)': cannot convert argument 1 from 'std::map<std::string,NestedContainer *,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>>' to 'std::initializer_list<std::pair<const _Kty,_Ty>>'
        with
        [
            _Kty=std::string,
            _Ty=NestedContainer
        ]
<source>(8): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
<source>(26): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'NestedContainer'
<source>(26): note: No constructor could take the source type, or constructor overload resolution was ambiguous
cl : Command line warning D9002 : ignoring unknown option '-std=c++20'
Compiler returned: 2

godbolt link

>Solution :

The values in your map are NestedContainer * (pointers), not NestedContainer. So you need to get pointers in the braced-initializer. Something like:

auto a = NestedContainer{
    {{"level1", new NestedContainer{
        {{"level2", new NestedContainer}} } }}
};

Alternately, remove the * from the std::map value type.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading