【发布时间】:2020-02-26 03:18:48
【问题描述】:
#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 类型的左值引用,则绑定将失败并且程序格式错误。 — 尾注 ]
所以等于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是一个标准的转换序列? -
@xskxzr 因为标准[dcl.init.list],构造函数被认为是直接初始化reuslt对象,隐蔽
0到int是A::A(整数) -
@xskxzr 或者换句话说,你认为
A a{0}是转换吗?
标签: c++ language-lawyer overload-resolution