假设您有以下课程:
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);
的已删除副本构造函数?
答案 0 :(得分:8)
如果你想= delete
复制构造函数,那么正确的形式是:A(const A&) = delete;
。看看你如何忘记const
? pair
可以与不可复制的类型一起使用,甚至是不可移动的类型。
您的实例化问题也可以通过以下方式证明:
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)
类
X
的隐式声明的复制构造函数将具有 形式X::X(const X&)
如果每个可能构造的类类型
形式M
的子对象(或 其数组)具有复制构造函数,其第一个参数是类型const M&
或const volatile M&
。否则,隐式声明 复制构造函数将具有X::X(X&)
因此,如果要隐式声明std::pair<A, int>
的复制构造函数,则其形式为pair::pair(pair &)
。
明确默认的功能
是一个特殊的会员功能,
具有相同的声明函数类型(可能不同的 ref-qualifier 除外,在复制构造函数的情况下除外) 复制赋值运算符,参数类型可以是“引用” 非const
T
“,其中T
是成员函数的类的名称)as 如果它已被隐式声明,没有默认参数。
由于声明pair(const pair&) = default;
没有与隐式声明的复制构造函数具有相同的声明函数类型,并且两个例外都不适用,因此程序格式错误。