GCC 上虚拟继承行为的奇怪默认空构造函数
Strange default empty constructor on a virtual inheritance behaviour on GCC
我的代码中有以下情况,派生 class 具有对基 class 的虚拟继承:
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) 给出以下错误:error: use of deleted function 'Derived::Derived()'
而 Clang (trunk) 编译它没有问题。
如果我将构造函数更改为 Derived() {}
而不是 Derived() = default
或者在 Base class.
上定义一个空构造函数,GCC 就会工作
为什么 = default
在这种情况下删除 GCC 中的函数?
Why is the = default removing the function in GCC in this case?
这是否是 GCC 中的错误(MSVC 的行为类似,但 clang-cl 按原样接受代码)是那些在 C++ 标准中研究更多的人的问题。但是,编译器似乎正在使用 = default
来暗示 Derived
构造函数依赖于(或者 等同于 )[=13] 的默认构造函数=] - 肯定被 删除,因为您定义了另一个(非默认)构造函数。
但是,显式添加您自己的 默认构造函数,Derived() {}
会删除隐含的依赖关系。
这通过指定(即取消删除)Base
class:
的默认构造函数来确认(在 GCC 和 MSVC 中)
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 {}
};
编辑:这也可能是相关的,甚至可能是重复的:Why is Default constructor called in virtual inheritance?
标准说(最新草案):
[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]]
只有一个规则可能适用于被删除的默认默认构造函数,这取决于基础是否是可能构造的子对象。
[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
是抽象的(因为它没有实现所有的纯虚函数),而Base
是虚基,所以基是不是 一个可能构造的子对象,因此原本应用于被删除的默认构造函数的唯一规则不适用,因此不应将其删除。编译器错误。
一个简单的解决方法(除了您已经提到的那些)是根本不声明 Derived::Derieved()
。在那种情况下,它似乎是正确地隐式生成的。
Adding the noexcept yields the error internal compiler error
这也是一个编译器错误。
我的代码中有以下情况,派生 class 具有对基 class 的虚拟继承:
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) 给出以下错误:error: use of deleted function 'Derived::Derived()'
而 Clang (trunk) 编译它没有问题。
如果我将构造函数更改为 Derived() {}
而不是 Derived() = default
或者在 Base class.
为什么 = default
在这种情况下删除 GCC 中的函数?
Why is the = default removing the function in GCC in this case?
这是否是 GCC 中的错误(MSVC 的行为类似,但 clang-cl 按原样接受代码)是那些在 C++ 标准中研究更多的人的问题。但是,编译器似乎正在使用 = default
来暗示 Derived
构造函数依赖于(或者 等同于 )[=13] 的默认构造函数=] - 肯定被 删除,因为您定义了另一个(非默认)构造函数。
但是,显式添加您自己的 默认构造函数,Derived() {}
会删除隐含的依赖关系。
这通过指定(即取消删除)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 {}
};
编辑:这也可能是相关的,甚至可能是重复的:Why is Default constructor called in virtual inheritance?
标准说(最新草案):
[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]]
只有一个规则可能适用于被删除的默认默认构造函数,这取决于基础是否是可能构造的子对象。
[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
是抽象的(因为它没有实现所有的纯虚函数),而Base
是虚基,所以基是不是 一个可能构造的子对象,因此原本应用于被删除的默认构造函数的唯一规则不适用,因此不应将其删除。编译器错误。
一个简单的解决方法(除了您已经提到的那些)是根本不声明 Derived::Derieved()
。在那种情况下,它似乎是正确地隐式生成的。
Adding the noexcept yields the error internal compiler error
这也是一个编译器错误。