为什么无法使用复制构造函数实例化"non const"而可以在没有复制构造函数的情况下实例化配对?



假设你有以下类:

struct A {
    A () {}
    A (A &) = delete;
};
int main() {
    std::pair<A, int> p1;
    return 0;
}

以下代码将无法编译(将-std=c++11g++ 一起使用(,并显示以下错误:

/

usr/include/c++/5/bits/stl_pair.h:在实例化"struct std::p air"时:

test.cpp:13:23:从这里需要

/

usr/include/c++/5/bits/stl_pair.h:127:17:错误:"constexpr std::p air<_T1, _T2>::p air(const std::p air<_T1, _T2>&( [带有 _T1 = A; _T2 = int]' 声明接受 const 引用,但隐式声明将采用 non-const

constexpr pair(const pair&) = default;

根据错误消息,我认为这是因为由于std::pair参数上的const限定符,无法实例化默认复制构造函数。

我可以理解为什么没有= delete就无法编译,因为不可能实例化采用std::pair const&参数的复制构造函数。

但是对于= delete,我希望编译器不会实例化这样的构造函数,因为它不能(据我所知(。实际上,此复制构造函数被删除,如以下代码所示:

std::pair<A, int> p1;
decltype(p1) p2(p1);

失败:

test.cpp:11:23:错误:使用已删除的函数"constexpr std::p air<_T1, _T2>::p air(const std::p air<_T1, _T2>&( [_T1 = A; _T2 = int]'

decltype(p1) p2(p1);

基本上,我的问题是:为什么编译器无法实例化已删除的std::pair复制构造函数?

[class.copy]/8:

X的隐式声明的复制构造函数将具有 形式

X::X(const X&)

如果类类型的每个潜在构造子对象M(或 数组(具有一个复制构造函数,其第一个参数的类型为 const M&const volatile M&.否则,隐式声明 复制构造函数将具有以下形式

X::X(X&)

因此,如果要隐式声明std::pair<A, int>的副本构造函数,它将具有 pair::pair(pair &) 的形式。

[dcl.fct.def.default]/1:

显式默认的函数应

  • 是一个特殊的成员函数,

  • 具有相同的声明函数类型(除了可能不同的 ref 限定符s,除了在复制构造函数或 复制赋值运算符,参数类型可以是"引用 non-const T ",其中 T 是成员函数类的名称( 作为 如果它被隐含地声明,并且

  • 没有默认参数。

由于声明pair(const pair&) = default;与隐式声明的复制构造函数不具有相同的声明函数类型,并且这两个异常都不适用,因此程序格式不正确。

如果要= delete复制构造函数,正确的形式是:A(const A&) = delete; 。看看你怎么忘记了那constpair可以与不可复制的类型一起使用,甚至可以与不可移动的类型一起使用。

您的实例化问题也可以通过以下方式演示:

struct A {
    A(A&) = delete;
};
struct B : A {
    B(const B&) = default;
};

或。。。

struct B {
    B(const B&) = default;
    A a;
};

基本上,pair = default它的复制 ctor,并将其定义为采用 const pair& ,但是您的一种类型将其定义为采用非 const &,因此默认生成失败,因为它无法将其 const&传递给您的非 const&。即使你的是= delete的,也没关系,它不会走那么远。

如果成员或基类不可复制,则默认复制 ctor 将有效删除。但是为了弄清楚这一点,它必须有一个能够调用的函数(即使该函数被删除(。在这些情况下,它不能将 const&传递给非 const&,因此它甚至无法确定您有一个已删除的副本 ctor。可以想象,可以编写标准中的一些内容来适应这种边缘情况。

最新更新