继承的构造函数不能用于复制对象

Inherited constructor cannot be used to copy object

此程序无法编译:

template <class T>
struct Base {
    Base();

    template <class U>
    Base(const Base<U>&);
};


template <class T>
struct Doh : Base<T> {
    using Base<T>::Base;
};


template <class T>
struct Derp : Base<T> {
    using Base<T>::Base;
};


Doh<void> x = Derp<void>();

错误消息显示 inherited constructor cannot be used to copy objectLive demo.

但是当我们将最后一行更改为此时,它会编译。

Doh<void> doh;
Doh<void> x1 = doh;
Doh<void> x2 = Derp<void*>();
Doh<void> x3(Derp<void>());

这三种情况都可以使用继承的构造函数。为什么?

因为这就是规定的工作方式。

[over.match.funcs/9] A constructor inherited from class type C ([class.inhctor.init]) that has a first parameter of type “reference to cv1 P” (including such a constructor instantiated from a template) is excluded from the set of candidate functions when constructing an object of type cv2 D if the argument list has exactly one argument and C is reference-related to P and P is reference-related to D.

这里D = Doh<void>C = Base<void>,感兴趣的构造函数是带有U = void的构造函数,它使P = Base<void>。该构造函数不可用,没有其他构造函数适合。

Doh<void> x1 = doh;

这没问题,因为它使用了 Doh<void> 的默认复制构造函数。

Doh<void> x2 = Derp<void*>();

这没关系,因为 Base<void*>Doh<void> 没有引用相关。

这种语言的“要点”是他们想要排除看起来像 copy/move 构造函数的东西。 Base 模板构造函数可能是贪婪的,并且比提供的或默认的 Derived copy/move 构造函数更匹配,这可能会令人惊讶。


已更新:

Doh<void> x3(Derp<void>());

这并没有声明和初始化一个Doh<void>。它声明了一个函数 x3 返回一个 Doh<void> 并接受一个参数,这是一个不接受参数和 returns Derp<void> 的函数。是“最头疼的解析”的典型例子。

要声明和初始化一个Doh<void>,可以使用大括号:

Doh<void> x3{Derp<void>()};

这无法按预期编译。