The given program is ill-formed for the reason(s) explained below.
C++20
B
is an aggregate. Since you're not explicitly initializing a
, dcl.init.aggr#5 applies:
- For a non-union aggregate, each element that is not an explicitly initialized element is initialized as follows:
5.2 Otherwise, if the element is not a reference, the element is copy-initialized from an empty initializer list ([dcl.init.list]).
This means that a
is copy initialized from an empty initializer list. In other word, it is as if we're writing:
A a = {}; // not valid see reason below
Note also that list-initialization in a copy initialization context is called copy-list-initialization which is the case here. And from over.match.list#1.2:
In copy-list-initialization, if an explicit constructor is chosen, the initialization is ill-formed.
Essentially, the reason for the failure is that A a = {};
is ill-formed.
C++11
Since B
is an aggregate and there are fewer initializer-clauses in the list than there are members in the aggregate, and from aggregate initialization documentation:
The effects of aggregate initialization are:
- If the number of initializer clauses is less than the number of members and bases (since C++17) or initializer list is completely empty, the remaining members and bases (since C++17) are initialized by their default member initializers, if provided in the class definition, and otherwise (since C++14) copy-initialized from empty lists, in accordance with the usual list-initialization rules (which performs value-initialization for non-class types and non-aggregate classes with default constructors, and aggregate initialization for aggregates).
This again means that a
is copy initialized from an empty list {}
. That is, it is as if we're writing:
A a = {}; // not valid see reason below
But from over.match.funcs:
In copy-list-initialization, if an explicit constructor is chosen, the initialization is ill-formed.
So again we face the same problem i.e., A a = {};
is not valid.
Solution
To solve this, we can pass A{}
or A{0}
as the initializer inside the list as shown below:
B b = { A{} }; //ok now
B c = { A{0} }; //also ok
Working demo.
Note
Note that writing A a{};
on the other hand is well-formed as this is a direct-initialization context and so it is direct-list-initialization.