使用嵌套映射的聚合初始化不按预期工作

huangapple go评论68阅读模式
英文:

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.

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,

<details>
<summary>英文:</summary>

It seems I was a bit fuzzy when posing this question since it have been a few days that I&#39;m trying to fix this problem and couldn&#39;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&#39;t compile for nested 
fields.
 
```cpp
struct NestedContainer;
struct NestedContainer {
  std::map&lt;std::string, NestedContainer *&gt; selections = std::map&lt;std::string, NestedContainer *&gt; ();
};

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

clang output

&lt;source&gt;:15:13: error: no matching constructor for initialization of &#39;std::map&lt;std::string, NestedContainer *&gt;&#39; (aka &#39;map&lt;basic_string&lt;char&gt;, NestedContainer *&gt;&#39;)
            {
            ^
/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 &#39;const std::less&lt;std::basic_string&lt;char&gt;&gt;&#39;
      map(const _Compare&amp; __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 &#39;const map&lt;basic_string&lt;char&gt;, NestedContainer *&gt;&#39;
      map(const map&amp;) = 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 &#39;map&lt;basic_string&lt;char&gt;, NestedContainer *&gt;&#39;
      map(map&amp;&amp;) = default;

gcc

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

msvc

example.cpp
&lt;source&gt;(14): error C2440: &#39;&lt;function-style-cast&gt;&#39;: cannot convert from &#39;initializer list&#39; to &#39;NestedContainer&#39;
&lt;source&gt;(14): note: No constructor could take the source type, or constructor overload resolution was ambiguous
cl : Command line warning D9002 : ignoring unknown option &#39;-std=c++20&#39;
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&lt;std::string, NestedContainer&gt; selections = std::map&lt;std::string, NestedContainer *&gt; ();
};

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

msvc

&lt;source&gt;:8:55: error: no viable conversion from &#39;map&lt;[...], NestedContainer *&gt;&#39; to &#39;map&lt;[...], NestedContainer&gt;&#39;
  std::map&lt;std::string, NestedContainer&gt; selections = std::map&lt;std::string, NestedContainer *&gt; ();
                                                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/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 &#39;std::map&lt;std::string, NestedContainer *&gt;&#39; (aka &#39;map&lt;basic_string&lt;char&gt;, NestedContainer *&gt;&#39;) to &#39;const map&lt;basic_string&lt;char&gt;, NestedContainer&gt; &amp;&#39; for 1st argument
      map(const map&amp;) = 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 &#39;std::map&lt;std::string, NestedContainer *&gt;&#39; (aka &#39;map&lt;basic_string&lt;char&gt;, NestedContainer *&gt;&#39;) to &#39;map&lt;basic_string&lt;char&gt;, NestedContainer&gt; &amp;&amp;&#39; for 1st argument
      map(map&amp;&amp;) = 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 &#39;std::map&lt;std::string, NestedContainer *&gt;&#39; (aka &#39;map&lt;basic_string&lt;char&gt;, NestedContainer *&gt;&#39;) to &#39;initializer_list&lt;value_type&gt;&#39; (aka &#39;initializer_list&lt;pair&lt;const std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt;&gt;, NestedContainer&gt;&gt;&#39;) for 1st argument
      map(initializer_list&lt;value_type&gt; __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&amp; __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&amp; __a)

gcc

&lt;source&gt;:8:60: error: could not convert &#39;std::map&lt;std::__cxx11::basic_string&lt;char&gt;, NestedContainer*&gt;()&#39; from &#39;map&lt;[...],NestedContainer*&gt;&#39; to &#39;map&lt;[...],NestedContainer&gt;&#39;
    8 |   std::map&lt;std::string, NestedContainer&gt; selections = std::map&lt;std::string, NestedContainer *&gt; ();
      |                                                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                                                            |
      |                                                            map&lt;[...],NestedContainer*&gt;
&lt;source&gt;: In function &#39;int main()&#39;:
&lt;source&gt;:26:4: error: could not convert &#39;{{{&quot;level1&quot;, {{{&quot;level2&quot;, &lt;brace-enclosed initializer list&gt;()}}}}}}&#39; from &#39;&lt;brace-enclosed initializer list&gt;&#39; to &#39;std::map&lt;std::__cxx11::basic_string&lt;char&gt;, NestedContainer&gt;&#39;
   26 |   });
      |    ^
      |    |
      |    &lt;brace-enclosed initializer list&gt;
ASM generation compiler returned: 1
&lt;source&gt;:8:60: error: could not convert &#39;std::map&lt;std::__cxx11::basic_string&lt;char&gt;, NestedContainer*&gt;()&#39; from &#39;map&lt;[...],NestedContainer*&gt;&#39; to &#39;map&lt;[...],NestedContainer&gt;&#39;
    8 |   std::map&lt;std::string, NestedContainer&gt; selections = std::map&lt;std::string, NestedContainer *&gt; ();
      |                                                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                                                            |
      |                                                            map&lt;[...],NestedContainer*&gt;
&lt;source&gt;: In function &#39;int main()&#39;:
&lt;source&gt;:26:4: error: could not convert &#39;{{{&quot;level1&quot;, {{{&quot;level2&quot;, &lt;brace-enclosed initializer list&gt;()}}}}}}&#39; from &#39;&lt;brace-enclosed initializer list&gt;&#39; to &#39;std::map&lt;std::__cxx11::basic_string&lt;char&gt;, NestedContainer&gt;&#39;
   26 |   });
      |    ^
      |    |
      |    &lt;brace-enclosed initializer list&gt;
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
&lt;source&gt;(8): error C2664: &#39;std::map&lt;std::string,NestedContainer,std::less&lt;_Kty&gt;,std::allocator&lt;std::pair&lt;const _Kty,_Ty&gt;&gt;&gt;::map(const std::map&lt;_Kty,_Ty,std::less&lt;_Kty&gt;,std::allocator&lt;std::pair&lt;const _Kty,_Ty&gt;&gt;&gt; &amp;)&#39;: cannot convert argument 1 from &#39;std::map&lt;std::string,NestedContainer *,std::less&lt;_Kty&gt;,std::allocator&lt;std::pair&lt;const _Kty,_Ty&gt;&gt;&gt;&#39; to &#39;std::initializer_list&lt;std::pair&lt;const _Kty,_Ty&gt;&gt;&#39;
        with
        [
            _Kty=std::string,
            _Ty=NestedContainer
        ]
&lt;source&gt;(8): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
&lt;source&gt;(26): error C2440: &#39;&lt;function-style-cast&gt;&#39;: cannot convert from &#39;initializer list&#39; to &#39;NestedContainer&#39;
&lt;source&gt;(26): note: No constructor could take the source type, or constructor overload resolution was ambiguous
cl : Command line warning D9002 : ignoring unknown option &#39;-std=c++20&#39;
Compiler returned: 2

godbolt link

答案1

得分: 3

您的映射中的数值是NestedContainer *(指针),而不是NestedContainer。因此,您需要在大括号初始化器中获取指针。类似于:

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

或者,从std::map值类型中删除*

英文:

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{
    {{&quot;level1&quot;, new NestedContainer{
        {{&quot;level2&quot;, new NestedContainer}} } }}
};

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

huangapple
  • 本文由 发表于 2023年5月28日 15:06:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/76350340.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定