Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/152.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在引用初始化中使用已删除的复制构造函数复制初始化_C++_C++11_Language Lawyer_Implicit Conversion_Reference Binding - Fatal编程技术网

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};