C++ 在引用初始化中使用已删除的复制构造函数复制初始化
考虑以下代码:C++ 在引用初始化中使用已删除的复制构造函数复制初始化,c++,c++11,language-lawyer,implicit-conversion,reference-binding,C++,C++11,Language Lawyer,Implicit Conversion,Reference Binding,考虑以下代码: #包括 类数据{ 公众: Data()=默认值; 数据(数据常量&)=删除; 数据(整数){ } }; int main(){ int a=0; const std::string&rs=“abc”//rs表示从字符数组初始化的临时副本 数据常数&d_rf=a;/#2,但此处可以遵守 //根据标准#2中的引用绑定到一个临时对象,临时副本由表达式初始化 } 如果T1或T2是类类型,并且T1与T2没有引用关系,则通过用户定义的转换([dcl.init]、[over.match.c
#包括
类数据{
公众:
Data()=默认值;
数据(数据常量&)=删除;
数据(整数){
}
};
int main(){
int a=0;
const std::string&rs=“abc”//rs表示从字符数组初始化的临时副本
数据常数&d_rf=a;/#2,但此处可以遵守
//根据标准#2中的引用绑定到一个临时对象,临时副本由表达式初始化
}
如果T1或T2是类类型,并且T1与T2没有引用关系,则通过用户定义的转换([dcl.init]、[over.match.copy]、[over.match.conv]),使用复制初始化类型为“cv1 T1”的对象的规则来考虑用户定义的转换;如果相应的非引用副本初始化格式不正确,则程序格式不正确。然后,调用转换函数的结果(如非引用副本初始化所述)用于直接初始化引用。对于此直接初始化,不考虑用户定义的转换 否则(即,对于剩余的复制初始化情况),可以从源类型转换为目标类型或(当使用转换函数时)转换为其派生类的用户定义转换将按[over.match.copy]中所述进行枚举,并通过重载解析([over.match])选择最佳转换。如果转换无法完成或不明确,则初始化格式错误。以初始值设定项表达式作为参数调用所选函数;如果函数是构造函数,则调用是目标类型的cv非限定版本的PR值,该目标类型的结果对象由构造函数初始化。调用用于根据上述规则直接初始化作为复制初始化目标的对象 根据该标准,
a
的类型是int
,初始化引用的类型是Data
,因此从int
到Data
,用户定义的转换考虑使用通过用户定义转换对“cv1 T1”类型的对象进行复制初始化的规则。它意味着数据常数&d_rf=a代码>可转换为数据临时=a;数据常数&d_rf=临时代码>。对于<代码>数据临时=a
,即使存在复制省略,也必须检查复制/移动构造函数是否可用,但是类数据
的复制构造函数已被删除,为什么可以遵守
下面是一些标准的引用
来自Enseignment
从CPP参考
如果引用是左值引用:
如果对象是左值表达式,且其类型为T或从T派生,且具有相同或更少的cv限定,则引用将绑定到左值标识的对象或其基类子对象。
如果对象是左值表达式,并且其类型隐式转换为T类型或从T派生的类型,相等或更少cv限定,则将考虑源类型及其返回左值引用的基类的非显式转换函数,并通过重载解析选择最佳转换函数。然后将引用绑定到转换函数返回的左值所标识的对象(或其基类子对象)
否则,如果引用是对常量的右值引用或左值引用:
如果对象是一个xvalue、一个类prvalue、一个数组prvalue或一个函数左值类型,它要么是T,要么是从T派生的,相等或更少cv限定,那么引用将绑定到初始值设定项表达式的值或它的基子对象。
如果对象是一个类类型表达式,可以隐式转换为xvalue、类prvalue或类型为T或从T派生的函数值,相等或更少cv限定,则引用将绑定到转换结果或其基子对象。
否则,将构造类型为T的临时副本,并从对象初始化副本。然后,该引用将绑定到此临时文件。复制初始化规则适用(不考虑显式构造函数)。
[示例:
const std::string&rs=“abc”//rs指从字符数组中初始化的临时拷贝
]
更新:
我们考虑
下的代码
根据该标准,值a
的类型是int
,引用的目标类型是数据
,因此编译器需要通过复制初始化生成一个临时类型数据
。这里毫无疑问,因此我们将重点放在拷贝初始化上。源类型为int
,目标类型为Data
,这种情况符合:
否则(即,对于剩余的复制初始化情况),用户定义的转换序列
可以从源类型转换为目标类型,或者(当转换函数
用于)的派生类,如13.3.1.4所述,最好的是
通过过载分辨率(13.3)选择。如果转换无法完成或不明确,则
初始化格式不正确。调用所选函数时,使用初始值设定项表达式作为其
论点如果函数是构造函数,则调用将初始化cv的临时值
目标类型的版本。临时值是一个pr值调用的结果(即
然后根据上述规则,使用临时(对于构造函数案例)来指导初始化,
作为复制初始化的目标的对象
$ g++ -Wall --std=c++11 -o toto toto.cpp
toto.cpp:14:8: error: copying variable of type 'Data' invokes deleted constructor
Data d = a; //#1
^ ~
toto.cpp:5:5: note: 'Data' has been explicitly marked deleted here
Data(Data const&) = delete;
^
1 error generated.
class Data{
public:
Data() = default;
Data(Data const&) = delete;
Data(int) {
}
};
class Data2{
public:
Data2() = default;
Data2(Data &) = delete;
Data2(int) {
}
};
int main()
{
Data a {5};
Data b = 5;
Data2 a2{5};
Data2 b2 = 5;
}
T x(a);
T x{a};