问题
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