GCC上虚拟继承行为的奇怪默认空构造函数



我的代码中有一个派生类与基类的虚拟继承的以下情况:

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 {}
};

链接:https://godbolt.org/z/bn1EY6

GCC(trunk(给出以下错误:error: use of deleted function 'Derived::Derived()',而Clang(truck(编译它时没有问题。

如果我将构造函数更改为Derived() {}而不是Derived() = default,或者在基类上定义一个空构造函数,GCC就会工作。

为什么= default在这种情况下会删除GCC中的功能?

标准说明(最新草案(:

[class.default.ctor]

类X的默认构造函数被定义为已删除,如果:

  • X是一个并集[[不适用]]
  • X是一个非并集类,它有一个带有[[不适用]]
  • 任何没有默认成员初始值设定项([class.mem](的非静态数据成员都是引用类型,[[不适用]]
  • const限定类型的任何非变体非静态数据成员[[不适用]]
  • X是并集并且[[不适用]]
  • X是一个非工会类,任何匿名工会成员的所有成员[[不适用]]
  • [如果基是潜在构造的子对象,则应用]任何潜在构造的个子对象,除了具有大括号或相等初始值设定项的非静态数据成员外,都具有类类型M(或其数组(,并且M没有默认构造函数或重载应用于查找M对应的分辨率([over.match](构造函数导致歧义或函数被删除或无法从默认默认构造函数访问,或
  • 任何潜在构造的子对象都有一个带析构函数的类型,该类型已从默认默认构造函数中删除或不可访问[[不适用]]

只有一条规则可能适用于要删除的默认构造函数,这取决于基是否是潜在构造的子对象

[特殊]

对于一个类,其非静态数据成员,其非虚拟直接基类,并且,如果该类不是抽象的([class.abstract](,则其虚拟基类被称为其潜在构造的子对象。

Derived是抽象的(因为它没有实现所有纯虚拟函数(,而Base是一个虚拟基,因此该基是而不是一个潜在的构造子对象,因此,原本适用于要删除的默认构造函数的唯一规则不适用,因此不应删除它。编译器错误。


一个简单的解决方法(除了您已经提到的方法之外(是根本不声明Derived::Derieved()。在这种情况下,它似乎是正确地隐式生成的。


添加noexcept会产生错误内部编译器错误

这也是一个编译器错误。

为什么在这种情况下=default会删除GCC中的函数

这是否是GCC中的一个错误(MSVC的行为类似,但clang cl接受代码(,这是C++标准中更多研究人员的问题。然而,编译器似乎使用= default来暗示Derived构造函数依赖于(或等效于(Base的默认构造函数,因为您定义了另一个(非默认(构造函数,所以肯定会删除该构造函数。

但是,使用Derived() {}显式添加您自己的默认构造函数可以删除隐含的依赖关系。

这是通过指定(即取消删除(Base类的默认构造函数来确认的(在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 {}
};

EDIT:这也可能是相关的,甚至可能是重复的:为什么在虚拟继承中调用Default构造函数?

相关内容

最新更新