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

这也是一个编译器错误。