【问题标题】:Is it possible to check if an abstract class is copy-constructible, ignoring abstractness?是否可以检查抽象类是否可复制构造而忽略抽象性?
【发布时间】:2020-04-03 16:27:01
【问题描述】:

考虑这些类:

struct A
{
    A(A &&) = default;
    A &operator=(A &&) = default;
    virtual void foo() = 0;
};

struct B
{
    virtual void bar() = 0;
};

AB 都不可复制构造(而且根本不可构造),但如果不是抽象的,B 将是可复制构造的。

是否可以编写一个类型特征来检查一个类是否有一个复制构造函数,它甚至适用于抽象类?

std::is_copy_constructible 不能在这里使用,因为抽象类是不可构造的。 std::is_copy_assignable 是一个合理的近似值,但对于具有复制构造函数但没有复制赋值的古怪类会失败,反之亦然。


为什么需要它:我有一个类似unique_ptr 的类,除其他外,它使用类型擦除来允许深度复制。深度复制(构造和赋值)要求存储的类型有一个复制构造函数。由于您可能还想在其中存储不可复制的类,因此如果其模板参数不是可复制构造的,则智能指针当前将停止可复制...如果模板参数是抽象类,即使它确实会无意中禁用复制有一个拷贝构造函数。

【问题讨论】:

  • 如果一个抽象类可以复制构造,则不能保证任何继承自它的类也是如此。
  • 不知道这是否可能,但您可以做的一件事是检查该类型是否具有clone 函数。这将是一个信号,您不应该复制,而是调用clone
  • @CássioRenan 是的,但至少对于这个智能指针类,我决定忽略它。尝试使用可复制模板参数将不可复制的类放入智能指针会触发static_assert

标签: c++


【解决方案1】:

应通过可通过基类型访问的virtual 成员函数调用通过指向基类型的指针(无论是否涉及unique_ptr)对动态类型进行的深度复制。您不应该尝试通过指向具有复制构造函数的基类型的指针来深度复制动态类型,因此复制构造函数的存在与否应该与您的代码无关。

在任何情况下,任何检查是否存在复制构造函数的表达式根据定义都必须构造该类型的值。如果是抽象的,那就不可能发生;任何这样的表达在那个基础上已经是无效的。真的没有办法解决这个问题。


深度复制(构造和赋值)要求存储的类型有一个复制构造函数。

不,它没有。可深度复制的类型只需要存储的类型具有 some 机制来创建其自身的适当动态实例,该实例可能属于其他类型。您选择要求存在复制构造函数。

正确的解决方案是停止做出使您的解决方案更难/不可能的选择。指向的类型可以是以下三种情况之一:

  1. 用户不想复制这种类型。
  2. 用户希望能够复制此类型。
  3. 用户希望能够复制(明显地)从该类型继承的动态类型的任何对象。让我们称之为“克隆”。

如何从不可复制和可复制中预测可克隆取决于您,但它必须是该类型的创建者使之成为可能的显式。您不能只假设用户的意图;他们必须以某种方式告诉你。并且这种确定需要以某种方式固有于所讨论的类型。如果您希望用户能够采用他们不拥有的类型并强制它是可克隆的,那么您可以使用特征类来允许他们从类本身之外声明该意图。

最终,将可克隆性作为运行时属性毫无意义。有时可克隆有时不可克隆的类型是没有意义的。即使克隆操作本身是通过赋予指针的函数指针来实现的(我不知道你为什么要这样做,因为对于使用相同的指针的不同实例,克隆类型的方式不应该不同type),判断该类型是使用普通复制还是克隆应该是该类型的内在和显式属性。

【讨论】:

  • 对我来说,拥有自定义智能指针的全部意义在于避免virtual 克隆函数。我通过在每个智能指针实例中存储一个额外的函数指针来“模拟”一个虚函数,该指针指向一个正确的克隆函数(使用适当的复制 ctor)。
  • @HolyBlackCat:你必须在构造时获得这个函数指针,并且它的实现必须匹配对象的实际动态类型。此外,您正在使整个指针类型变大两倍,而不是仅仅使用任何抽象类型由于......抽象而已经拥有的 vtable。如果它不是抽象的,它就不需要可克隆的接口;复制构造函数应该没问题。
  • 感谢您对我不知道自己需要的“代码”审查。 :P “你必须在构造时得到这个函数指针......对于指针的不同实例,你克隆类型的方式不应该不同”我在构造函数中设置了那个指针,但它指向的函数是由模板自动生成的。用户不能直接设置指针。这是这个智能指针的early implementation
  • “你让你的整个指针类型变大了两倍” 是的,也许这不是最好的主意。尽管如果该类型不是可克隆的,则必须存储额外的指针(常规指针或 vtable 指针)似乎是不可避免的。
猜你喜欢
  • 2011-01-08
  • 2020-06-07
  • 2013-11-17
  • 1970-01-01
  • 1970-01-01
  • 2012-06-25
  • 1970-01-01
  • 1970-01-01
  • 2012-11-18
相关资源
最近更新 更多