Why can't a 2D std::array be initialized with two layers of list-initializers?

蹲街弑〆低调 提交于 2019-12-22 04:06:17

问题


can someone help me understand why my compiler can't/doesn't deduce this? (using g++ 7.3)

Does not work:

#include <array>
std::array<std::array<double,2>,2> f() {
 return {{0,0},{0,0}};
}

Works fine:

#include <array>
std::array<std::array<double,2>,2> f() {
 return {std::array<double,2>{0,0},{0,0}};
}

Also weirdly this fails too:

#include <array>
std::array<std::array<double,2>,2> f() {
 return std::array<std::array<double,2>,2>{{0,0},{0,0}};
}

@1201ProgramAlarm pointed out that adding another set of curly braces works:

#include <array>
std::array<std::array<double,2>,2> f() {
 return {{{0,0},{0,0}}};
}

It's using aggregate initialization, because std::array has no constructor for brace-init-list. That's fine, but then why/how does this work?

std::array<double,2> x{1,2};

why does it handle this case but not the nested case?


回答1:


The container std::array is equivalently a struct holding a C-array (an implementation may not implement std::array in this way, but it should guarantee the semantic is the same), so it should be initialized by two layers of braces, i.e.

#include <array>
std::array<std::array<double,2>,2> f() {
   return {{{{0,0}},{{0,0}}}};
} 

Of course, braces in an initializer-list can be elided like what we usually do for a 2D array:

int arr[2][2] = {0,1,2,3};

... but the initializer-list that begins with the elided braces before the elision should not begin with a left brace after the elision. In other words, if an initializer-list begins with a left brace, the compiler will not consider the possibility that this initializer-list has elided outermost braces.

In your initializer {{0,0},{0,0}}, the sub-initializer {0,0},{0,0} begins with a left brace, so it is used to initialize the C-array itself. However, there are two clauses in the list while there is only one C-array, an error occurs.

In your initializer {std::array<double,2>{0,0},{0,0}}, the sub-initializer std::array<double,2>{0,0},{0,0} does not begin with a left brace, so it can be used to initialize the elements of the C-array, which is OK (recursively, {0,0} is OK to initialize an std::array<double,2> because the sub-initializer 0,0 does not begin with a left brace).


A suggestion: with this elision rule of braces, you can elide all inner braces, just like what we usually do for a 2D array:

#include <array>
std::array<std::array<double,2>,2> f() {
   return {0,0,0,0};
} 


来源:https://stackoverflow.com/questions/52231566/why-cant-a-2d-stdarray-be-initialized-with-two-layers-of-list-initializers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!