I have this example
struct B { B(); };
struct D : B { };
D d{ B() }; // what happens here? or why it's well-formed
This is an aggregate initialization, but I can't understand how d
is constructed? Does the compiler generates implicitly a copy constructor with this signature D::D(const D&)
or D::D(const B&)
or what? It's clear that the compiler does not generate D::D(const D&)
because const D& = B()
is ill-formed. So this means it generates a copy constructor D::D(const B&)
?
Now what would happen if I inherits constructors from B
:
struct B { B(); };
struct D : B { using B::B; };
D d{ B() }; // why it's ill-formed?
One said to me that the default copy constructor of B
which is B::B(const B&)
is inherited into D
but it's excluded from the set of candidates, that's why it's ill-formed. Is that true?
CodePudding user response:
Can the compiler generates a default copy constructor that takes reference to different class type?
By definition, no. A constructor that accepts an object of another type is not a copy constructor. It would be a converting constructor.
No such converting constructor is implicitly generated.
This is an aggregate initialization, but I can't understand how d is constructed?
No constructor of the enclosing class is called in aggregate initialisation. The sub objects are initialised directly.
D
is an aggregate with a base class of type B
. Aggregate initialisation is used to initialise this base sub object.
It's clear that the compiler does not generate D::D(const D&) because const D& = B() is ill-formed.
Former cannot be deduced from the latter. In fact, there is a (trivial) D::D(const D&)
which you can prove by attempting copy initialisation:
D d1{};
D d2(d1); // works
That said, a trivial constructor is a concept for the abstract machine, and the compiler doesn't have to generate anything in practice.
Now what would happen if I inherits constructors from B
struct D : B { using B::B; }; D d{ B() }; // why it's ill-formed?
Having inherited constructors disqualifies the class from being an aggregate and hence aggregate initialisation does not apply. List initialisation will attempt to call a constructor, but no converting constructor exists.