As written, this is aggregate initialization. The applicable rule is (§8.5.1 [dcl.init.aggr]/p7):
If there are fewer initializer-clauses in the list than there are
members in the aggregate, then each member not explicitly initialized
shall be initialized from its brace-or-equal-initializer or, if
there is no brace-or-equal-initializer, from an empty initializer
list (8.5.4).
The relevant parts of §8.5.4 [dcl.init.list]/p3 is:
List-initialization of an object or reference of type T
is defined
as follows:
- If
T
is an aggregate, aggregate initialization is performed (8.5.1).
- Otherwise, if the initializer list has no elements and
T
is a class type with a default constructor, the object is
value-initialized.
- [irrelevant items omitted]
- Otherwise, if the initializer list has no elements, the object is value-initialized.
In short, sub-aggregates are recursively aggregate-initialized from an empty initializer list. Everything else is value-initialized. So the end result is everything being value-initialized, with everything being a POD, value-initialization means zero-initialization.
If T
is POD but not an aggregate, then aggregate initialization doesn't apply, so you hit the second bullet point in §8.5.4 [dcl.init.list]/p3, which results in value-initialization of the entire object instead. POD classes must have a trivial (and so not-user-provided) default constructor, so value-initialization for them means zero-initialization as well.