c++ - 复制列表初始化的隐式转换等级是多少
问题描述
#include <iostream>
struct A{
A(int){
}
};
struct B{
B() = default;
B(A){
}
B(B const&){}
B(B&&){}
};
int main(){
B b({0});
}
对于给定的代码,候选函数是:
#1 B::B(A)
#2 B::B(const B&)
#3 B::B(B&&)
根据标准,对于#1,类型A的对象由{0}复制列表初始化,因为A a = {0}
,A::A(int)
被认为是初始化,所以只有#1内的标准转换。对于#2,它是引用表单的初始化,braced-init-list
这是[dcl.init.list]的原因
否则,如果 T 是引用类型,则生成 T 引用的类型的纯右值。prvalue 通过复制列表初始化或直接列表初始化来初始化其结果对象,具体取决于引用的初始化类型。然后使用纯右值直接初始化引用。[注意:像往常一样,如果引用类型是对非常量类型的左值引用,则绑定将失败并且程序格式错误。——尾注]
所以它等同于const B& = {0}
,在这个初始化中,转换函数是B::B(A)
,参数是0
,所以B tmp = {0}
'B::B(A)' 被认为参数是由参数初始化的0
,因为A parameter = 0
。
否则(即,对于剩余的复制初始化情况),可以从源类型转换到目标类型或(当使用转换函数时)到其派生类的用户定义转换序列被枚举,如 [over .match.copy],并通过重载决议选择最好的...
所以#2里面有一个用户自定义的转换,#3的情况和#2一样,根据[over.ics.rank],
标准转换序列是比用户定义的转换序列或省略号转换序列更好的转换序列,并且...
标准转换比自定义转换好,所以#1应该比#2和#3好,但实际上,g++报告调用不明确,为什么?错误信息是:
main.cpp: In function ‘int main()’:
main.cpp:12:10: error: call of overloaded ‘B(<brace-enclosed initializer list>)’ is ambiguous
B b({0});
^
main.cpp:8:3: note: candidate: B::B(A)
B(A){
^
main.cpp:6:8: note: candidate: constexpr B::B(const B&)
struct B{
^
main.cpp:6:8: note: candidate: constexpr B::B(B&&)
解决方案
所有三个转换{0} -> A
, {0} -> const B&
,{0} -> B&&
都是用户定义的转换。
要转换{0}
为A
,会发生另一个重载决议,这一次您面对三个构造函数A(int)
,A(const A&)
并且A(A&&)
. 由于0 -> int
是标准转换,而两者0 -> const A&
都是0 -> A&&
用户定义的转换,因此转换0 -> int
获胜并被A(int)
选择转换{0}
为A
.
您的困惑来自混合两种重载解决方案。
推荐阅读
- javascript - 变换比例时如何检查元素是否在视口之外
- javascript - 在我的网页密码中包含“&”符号打破密码
- amazon-web-services - AWSIOT Pubsub 模型的开销时间是多少?
- ios - 在ios中显示上传图片的状态
- python - python '\xb4' 编码问题
- c# - 我将枚举作为一对夫妇使用是一种不好的做法吗?
- python - 连接大型数据帧时出现 MemoryError
- yii2 - Yii2框架的右连接
- html - 有没有办法突出显示单击的垫选项卡?当每个 mat-tab 是动态生成的
- elasticsearch - 如何在索引之前删除单词之间的空格