为什么使用声明的继承构造函数不使用默认构造函数初始化虚拟基class?

Why does using-declared inheriting constructor NOT initialize the virtual base class using a default constructor?

我偶然发现了一个 question of the using-declared inheriting constructor yesterday. And after carefully reading the answer as well as the linked standard draft N3337,我发现当直接基础 class 也使用 using 从虚拟基地。

这是一个例子:

struct A
{
    A(int, int){}
};

struct B : virtual A
{
    using A::A;
};

struct C : virtual A
{
    using A::A;
};

struct BC : B, C
{
    using B::B;
    using C::C;
}; 

// Now if we define an inline constructor that does the same
// as the constructor B inherited...
struct BB : virtual A
{
    BB(int a, int b):A(a,b){}
};

struct BBC : BB, C
{
    using BB::BB;
    using C::C;
};

int main()
{
    BC(1, 1);  // this compiles
    BBC(1, 1); // this doesn't because it needs to defaultly
               // initialize the virtual base A who doesn't
               // have a default constructor
}

我理解为什么 BBC 无法编译,具体原因由上面的答案提供,我将在这里重复 [class.inhctor]/8

An implicitly-defined inheriting constructor performs the set of initializations of the class that would be performed by a user-written inline constructor for that class with a mem-initializer-list whose only mem-initializer has a mem-initializer-id that names the base class denoted in the nested-name-specifier of the using-declaration and an expression-list as specified below, and where the compound-statement in its function body is empty ([class.base.init]).

[class.base.init]/10

In a non-delegating constructor, initialization proceeds in the following order: First, and only for the constructor of the most derived class ([intro.object]), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list.

所以基本上虚基 class 需要默认构造,因为它不在 [=13= 的继承构造函数的 mem-initializer-list 中].但是 A 没有默认构造函数,所以它失败了(添加 A()=default; 显然可以使其编译,但这不是这里的重点)。

但是我还不清楚为什么BC没有这个问题?它本质上是 Inheriting constructors 部分中的 the same example given by cppreference。所以它必须工作。但这看起来不与标准相矛盾吗?当 BA 继承构造函数时,它也只获得非默认构造函数,它执行与 BB 中定义的构造函数相同的初始化,除了是隐式的。然后,当 B 的这个构造函数被 BC 进一步继承时,是否应该应用相同的规则,其中 A 将被默认构造,因此无法编译?

编辑:@j6t 指出我在看一份过时的标准草案。 new one 确实更符合我之前找到的 cppreference 页面。

我仍然不清楚的一件事是,它确实解释了如果选择了虚拟基础构造函数会发生什么,但是它首先是如何被孙子 class BC 继承的?从同一个 draft 来看,using 引入的虚基构造函数似乎只会在派生的 class 中考虑(在本例中为 B)。 BC 中的 using 是如何继承上两层的构造函数的?

我期望的是,当BC使用-声明构造函数时,最初由BA继承的应该首先被视为B构造函数,然后被BC继承。但事实并非如此。

我只是在编辑中回答你的问题。

... but how is [the virtual base constructor] inherited by the grandchild class BC in the first place?

你引用的 paragraph 说:

Constructors that are introduced by a using-declaration are treated as though they were constructors of the derived class when looking up the constructors of the derived class (class.qual) [...].

也就是说,这些构造函数是通过限定名称查找找到的。这使得 using 声明有效地成为递归操作:要在基 class 中查找事物,它使用限定名称查找,然后使它找到的事物可用于限定名称查找。

struct B 使用 using A::A 时,它使构造函数 A::Astruct B 中查找构造函数时可用。当 struct BC 使用 using B::B 时会发生这种情况;这是 struct B 中名称 B 的限定查找;因此,它找到构造函数 A::A,并以这种方式使 A::Astruct BC.

中可用