为什么删除的复制构造函数不允许使用其他具有多态类型的构造函数?

Why deleted copy constructor doesn't let to use other constructor with polymorphic type?

我想知道为什么这个程序不能编译(在 msvc、gcc 和 clang 上的行为相同):

#include <iostream>

using namespace std;

struct Action
{
    virtual void action()
    {
        cout << "Action::action()\n";
    }
};

struct ActionDecorator : Action
{
    ActionDecorator(const ActionDecorator&) = delete;
    ActionDecorator(Action & action) : origAction(action)
    {
    }

    void action() override
    {
        decoration();
        origAction.action();
    }

private:
    void decoration()
    {
        cout << "ActionDecorator::decoration()\n";
    }

    Action & origAction;
};

int main()
{
    Action action;
    ActionDecorator actionDecorator(action);
    ActionDecorator actionDecorator2(actionDecorator);
    actionDecorator2.action();
}

按照我的预期,删除的复制构造函数应该让其他ActionDecorator实例构造ActionDecorator,因为它是Action的多态类型。相反,我必须将 ActionDecorator 实例显式转换为 Action&,因为编译器抱怨试图引用已删除的复制构造函数。是否有一些标准规则可以解释这种行为?

删除函数不会将其从重载决议中删除。该函数只是 defined 被删除。目的是让程序ill-formed重载解析时选择那个函数.

由于复制 c'tor 比您提供的特殊基础 class c'tor 更匹配,如果您不转换,重载解析将始终选择它。

如何最好地处理它是值得商榷的。您可以理论上 让副本执行类似的包装。然而,我对有一个不复制的复制者感到痛苦。你的米数可能非常。

我个人更喜欢的另一种选择是不按原样提供 public 构造函数。相反,让客户通过常规命名函数创建装饰器。像这样:

ActionDecorator decorate(Action& action) {
  return {action};
}

现在class可以真正保持non-copyable,客户再也不需要自己投了。如果他们将 ActionDecorator 传递给 decorate,它将在构造实例之前绑定到 Action 引用。所以它甚至不会考虑复制c'tor。

然而,class 必须是可移动的,才能在 C++17 之前工作。