为什么不能用“非const”复制构造函数实例化对,而可以实例化一个没有?

时间:2016-03-25 15:48:13

标签: c++ c++11 constructor

假设您有以下课程:

struct A {
    A () {}
    A (A &) = delete;
};

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

以下代码无法编译(使用带有-std=c++11的{​​{1}})并出现以下错误:

  

/ usr / include / c ++ / 5 / bits / stl_pair.h:在'struct std :: pair'的实例化中:

     

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

     

/ usr / include / c ++ / 5 / bits / stl_pair.h:127:17:错误:'constexpr std :: pair&lt; _T1,_T2&gt; :: pair(const std :: pair&lt; _T1,_T2&gt;&amp; ;)[与_T1 = A;声明采用const引用的_T2 = int]',但隐式声明将采用非const

g++

根据错误消息,我认为这是因为由于constexpr pair(const pair&) = default; 参数上的const限定符,无法实现默认的复制构造函数。

我可以理解为什么在没有std::pair的情况下不会编译,因为不可能实现带有= delete参数的复制构造函数。

但是对于std::pair const&,我希望编译器不会实例化这样的构造函数,因为它不能(据我所知)。实际上,这个拷贝构造函数被删除,如下面这段代码所示:

= delete

失败了:

  

test.cpp:11:23:错误:使用已删除的函数'constexpr std :: pair&lt; _T1,_T2&gt; :: pair(const std :: pair&lt; _T1,_T2&gt;&amp;)[with _T1 = A ; _T2 = int]'

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

基本上,我的问题是:为什么编译器无法实例化decltype(p1) p2(p1); 的已删除副本构造函数?

2 个答案:

答案 0 :(得分:8)

如果你想= 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&amp ;,所以默认生成失败,因为它无法传递它的const&amp;到你的非常数和...即使你的= delete被编辑,也没关系,但它没有那么远。

如果成员或基类不可复制,则有效删除默认副本。但为了弄明白这一点,它必须有一个能够调用的函数(即使该函数被删除)。在这些情况下,它不能通过const&amp;一个非常数和一个所以它甚至无法弄清楚你有一个删除的副本ctor。可以想象,可以编写标准中的某些内容以适应这种边缘情况。

答案 1 :(得分:8)

[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-qualifier 除外,在复制构造函数的情况下除外)   复制赋值运算符,参数类型可以是“引用”   非const T“,其中T是成员函数的类的名称)as   如果它已被隐式声明,

  •   
  • 没有默认参数。

  •   

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