I am trying to understand the changes that happened from C++14 to C++17 regarding aggregate initialization. From §9.4.2[dcl.init.aggr]/2:
The elements of an aggregate are:
- (2.1) for an array, the array elements in increasing subscript order, or
- (2.2) for a class, the direct base classes in declaration order, followed by the direct non-static data members ([class.mem]) that are not members of an anonymous union, in declaration order.
This paragraph defines what the elements of an aggregate class are. In particular, I can't get what the bold sentence means. I have this example to demonstrate my confusion:
struct Base { int mem1, mem2; };
struct Derived : Base { int mem3, mem4; };
Derived obj = { 1, 2, 3, 4 };
The object obj
is an aggregate since it satisfies the criteria defined in [dcl.init.aggr]/1. My problem, however, is what are the elements of this aggregate. It seems that the elements are Base::mem1
initialized with 1, Base::mem2
initialized with 2, Derived::mem3
initialized with 3, and Dervied::mem4
initialized with 4.
But [dcl.init.aggr]/2 states the opposite. It is said that the elements are the data members of the direct base classes, which is Base
in this case, followed by the direct non-static data members of the Derived
class. Am I parsed the wording correctly?.
I really don't know whether or not I understood the quote correctly, but I think I don't. So any explanation regarding this point will help me alot.
Your understanding of the concept "elements of an aggregate" is correct. However, that's not the end of aggregate initialization. There is brace elision:
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.
All implicit type conversions ([conv]) are considered when initializing the element with an assignment-expression. If the assignment-expression can initialize an element, the element is initialized. Otherwise, if the element is itself a subaggregate, brace elision is assumed and the assignment-expression is considered for the initialization of the first element of the subaggregate.
Since Base b = 1;
is not a valid initialization statement, brace elision is assumed, as defined in the first paragraph.