没有默认ctor的间接虚拟基会阻止子级拥有默认ctor,除非中间的每个类也有一个

  • 本文关键字:默认 ctor 中间 有一个 拥有 虚拟 c++
  • 更新时间 :
  • 英文 :


我很抱歉标题晦涩难懂,不知道如何更好地表达。

考虑以下继承层次结构:

struct A
{
A(int) {}
};
struct B : virtual A
{
B() : A(42) {}
};
struct C : B
{
C() : A(43) {}
};

它确实有效。现在让我们说,我想创建一个可以透明地注入层次结构中间的模板,如下所示:

template <typename ...P>
struct Proxy : P...
{
// This constructor doesn't change anything. It was added
// to indicate that `Proxy` should only be used as a base.
protected:
Proxy() = default;
};
struct D : Proxy<B>
{
D() : A(44) {}
};

这给了我:error: call to implicitly-deleted default constructor of 'Proxy<B>'

在gcc.godbolt.org上运行

我理解发生了什么:Proxy不能有默认的构造函数,因为它没有为A提供初始化器,因此派生类不能默认构造Proxy

但仔细想想,这是没有意义的,因为即使我在Proxy中为A提供了一个初始化器,D也会忽略它,并且必须提供自己的初始化器。

如何绕过此限制?

代码中的所有内容都可以更改,但我更喜欢侵入性较小的更改。


在我的实际代码中,只有一个基类会导致这些问题,所以我为Proxy(与requires不同(创建了两个不同的默认构造函数:一个什么都不做,另一个(当P...中的任何一个实际上继承自A时使用(将一个伪参数传递给A::A(int)

但我不喜欢这个解决方案,因为它不是通用的,所以我正在寻找更好的替代方案。

[special]/7:

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

[class.default.cctor]/2.7表示,如果

任何潜在构建的子对象,非静态数据除外具有大括号或相等初始值设定项的成员,具有类类型M(或数组其(并且M没有默认构造函数或重载应用于查找M对应的分辨率([over.match](构造函数导致歧义或函数被删除或无法从默认的默认构造函数访问

因此,我们可以通过使Proxy抽象来从潜在构建的子对象集中排除虚拟基,例如,通过使析构函数纯虚拟(但仍提供定义(:

template <typename ...P>
struct Proxy : P...
{
protected:
virtual ~Proxy() = 0;
Proxy() = default;
};
template <typename ...P>
Proxy<P...>::~Proxy() = default;

相关内容

最新更新