I have the following situation of a Derived class with virtual inheritance to a Base class in my code:
class Base {
int x;
public:
Base(int x): x{x} {}
virtual void f() = 0;
};
class Derived : public virtual Base {
public:
Derived() = default;
};
class Concrete: public Derived {
public:
Concrete(): Base{42} {}
void f() override {}
};
Link: https://godbolt.org/z/bn1EY6
GCC (trunk) gives the following error: error: use of deleted function 'Derived::Derived()'
while Clang (trunk) compiles it without a problem.
GCC works if I change the constructor to Derived() {}
instead of Derived() = default
or define an empty constructor on the Base class.
Why is the = default
removing the function in GCC in this case?
Standard says (latest draft):
[class.default.ctor]
A defaulted default constructor for class X is defined as deleted if:
- X is a union that ... [[does not apply]]
- X is a non-union class that has a variant member M with ... [[does not apply]]
- any non-static data member with no default member initializer ([class.mem]) is of reference type, [[does not apply]]
- any non-variant non-static data member of const-qualified type ... [[does not apply]]
- X is a union and ... [[does not apply]]
- X is a non-union class and all members of any anonymous union member ... [[does not apply]]
- [applies if the base is a potentially constructed subobject] any potentially constructed subobject, except for a non-static data member with a brace-or-equal-initializer, has class type M (or array thereof) and either M has no default constructor or overload resolution ([over.match]) as applied to find M's corresponding constructor results in an ambiguity or in a function that is deleted or inaccessible from the defaulted default constructor, or
- any potentially constructed subobject has a type with a destructor that is deleted or inaccessible from the defaulted default constructor. [[does not apply]]
Only one rule potentially applies for the defaulted default constructor being deleted, and it depends on whether the base is a potentially constructed subobject.
[special]
For a class, its non-static data members, its non-virtual direct base classes, and, if the class is not abstract ([class.abstract]), its virtual base classes are called its potentially constructed subobjects.
Derived
is abstract (because it doesn't implement all pure virtual functions), and Base
is a virtual base, therefore the base is not a potentially constructed subobject, and therefore the only rule that would otherwise have applied for the defaulted constructor being deleted does not apply and thus it should not be deleted. The compiler is wrong.
A simple workaround (besides those that you already mentioned) is to no declare Derived::Derieved()
at all. It seems to be correctly implicitly generated in that case.
Adding the noexcept yields the error internal compiler error
This is also a compiler bug.
Why is the = default removing the function in GCC in this case?
Whether or not this is a bug in GCC (MSVC behaves similarly but clang-cl accepts the code, as is) is a matter for those more studied in the C++ Standards. However, it appears that the complier is taking the = default
to imply that the Derived
constructor depends on (or is equivalent to) the default constructor for Base
- which is definitely deleted, as you have defined another (non-default) constructor.
However, explicitly adding your own default constructor, with Derived() {}
removes that implied dependency.
This is confirmed (in GCC and MSVC) by specifying (i.e. undeleting) the default constructor for the Base
class:
class Base {
int x;
public:
Base() : x{0} {} // Adding this removes the error!
// Base() = default; // Also works
Base(int x): x{x} {}
virtual void f() = 0;
};
class Derived : public virtual Base {
public:
Derived() = default;
};
class Concrete: public Derived {
public:
Concrete(): Base{42} {}
void f() override {}
};
EDIT: This may also be relevant, or even a possible duplicate: Why is Default constructor called in virtual inheritance?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With