Given following code:
struct B {int i[2];};
struct A {B b[2];};
int main() {
A{{0, 0}, {0, 0}}; //too many initializers for ‘A’
A{{0, 0}, B{0, 0}}; //too many initializers for ‘A’
A{B{0, 0}, {0, 0}};
A{B{0, 0}, B{0, 0}};
}
Why would the first two not compile? I think all four lines should mean the same thing since they're all one-to-one mapping?
(The test is compiled using g++ 13.2.0 -std=c++20.)
For example, I don't think
A{{0, 0}, {0, 0}}
has any ambiguity?
Let us look at [dcl.init.aggr]/16
:
Braces can be elided in an initializer-list as follows. If the initializer-list begins with a left brace, then the succeeding comma-separated list of initializer-clauses initializes the elements of a subaggregate; it is erroneous for there to be more initializer-clauses than elements. If, however, the initializer-list for a subaggregate does not begin with a left brace, then only enough initializer-clauses from the list are taken to initialize the elements of the subaggregate; any remaining initializer-clauses are left to initialize the next element of the aggregate of which the current subaggregate is an element.
The parsing seems to go as follows:
A{{0, 0}, {0, 0}}
// ^ Entering `A`
A{{0, 0}, {0, 0}}
// ^ Entering `b`
A{{0, 0}, {0, 0}}
// ^ Entering `b[0]`, the opening brace is omitted.
// ^ Initializing `b[0].i[0]`
A{{0, 0}, {0, 0}}
// ^ Initializing `b[0].i[1]`
A{{0, 0}, {0, 0}}
// ^ Exiting `b[0]`
// ^ Exiting `b`
A{{0, 0}, {0, 0}}
// ^ `A` has no more fields, expected `}`