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

Luc*_*ski 6 c++ gcc clang virtual-inheritance

我的代码中有以下情况,即派生类具有对基类的虚拟继承:

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 {}
};
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

eer*_*ika 2

标准说(最新草案):

[类.default.ctor]

如果满足以下条件,则类 X 的默认构造函数被定义为已删除:

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

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

[特别的]

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

Derived是抽象的(因为它没有实现所有纯虚函数),并且Base是虚拟基类,因此基类不是潜在构造的子对象,因此适用于被删除的默认构造函数的唯一规则不适用因此不应将其删除。编译器是错误的。


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


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

这也是一个编译器错误。