Bite by this constructor resolution rule:
1) D is an aggregate From
[dcl.init.aggr]
§11.6.2/1 (C++23 draft N4950):
An aggregate is an array or a class with no user-declared or inherited constructors… (…) A class is an aggregate even if it has base classes.
So `class D : public Base {}` is an aggregate.
2) Aggregate initialization rule From
[dcl.init.aggr]
§11.6.2/4:
If the aggregate has a base class, each base class is initialized in the order of declaration using the corresponding elements of the initializer list.
So the single element {42.3} is forwarded to the base class Base.
3) [class.base.init] §12.6.2/2:
In a non-delegating constructor, if a given potentially constructed subobject is not designated by a mem-initializer, then it is initialized as follows:
— if the entity is a base class, the base class’s default constructor is called,
unless otherwise specified by the rules of aggregate initialization.
And aggregate initialization rules (step 2) say the base is initialized from the element. That means the base is constructed as if by direct-initialization with that element.
4) Constructor overload resolution
Now, how does Base itself get constructed from 42.3?
That’s governed by [dcl.init] §11.6.1/17:
If the initializer is a parenthesized expression-list or a braced-init-list,
constructors are considered.
The applicable constructors are selected by overload resolution ([over.match.ctor]).
So the compiler now does overload resolution among Base(int) and Base(double). The best match for 42.3 is Base(double).
#include <iostream>
class Base {
public:
// mark as `explicit` prevents derived type picking up this constructor
Base(int) {
std::cout << "base int\n";
}
// mark as `explicit` prevents derived type picking up this constructor
Base(double) {
std::cout << "base float\n";
}
};
class D : public Base {
};
int main() {
D d = {42.3}; // works
// D d = 42.3; // failed, unless `using Base::Base;`
}
#include <iostream>
class Base {
public:
Base(double, int) {
std::cout << "base double, float\n";
}
};
class Base2 {
public:
Base2(double, int) {
std::cout << "base2 double, float\n";
}
};
class D : public Base, public Base2 {
};
int main() {
D d = {{42.3, 42}, {42.4, 42}};
}
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.