考虑简单的代码:
struct A;
struct B {
B(){}
B(A const&){ }
};
struct A {
operator int() const {return 0;};
};
void func(B){}
void func(char){}
int main()
{
func(A()); //ambiguous call oO
}
首先,我不确定我是否理解正确的一切,所以请在我发现错误的时候纠正我。
我的理解是应该选择void func(B)
,因为func
的参数是A
类型,因此所需的转换类型是“用户定义的转换序列”< / p>
现在来自IBM C ++ ref:
用户定义的转换序列包含以下内容:
- 标准转换序列
- 用户定义的转化
- 第二个标准转换序列
现在有两个用户定义的转换
B::B(const A&)
和A::operator int (const A&);
所以序列是
- &GT; A()
- &gt; B::B(const A&)
- &gt; Standard conversion (identity conversion)
- &GT; A()
- &gt; A::operator int (const A&)
- &gt; Standard conversion (integral conversion)
因为积分转换比身份转换更差,我认为void func(B)
会调用,但调用仍然不明确。
所以,请帮助我,我错了,为什么电话不明确。非常感谢:)
答案 0 :(得分:6)
此处的两个转换序列A -> B
和A -> int
都是用户定义的,因为它们是通过您定义的函数运行的。
用户定义的转换序列排序规则见13.3.3.2(N3797):
用户定义的转换序列
U1
是一个比另一个用户定义的转换序列U2
更好的转换序列,如果它们包含相同的用户定义转换函数或构造函数,或者它们初始化相同的类聚合初始化,在任何一种情况下,U1
的第二个标准转换序列优于U2
的第二个标准转换序列
这两个转换序列不包含相同的用户定义转换函数,并且它们不会在聚合初始化中初始化相同的类(因为一个初始化int
)。
因此,一个序列排在另一个序列之上并不是真的,因此这个代码是不明确的。
答案 1 :(得分:3)
所以序列是 - &gt; A() - &gt; B :: B(常数A&amp;) - &gt;标准转换(身份转换)
没有!摘自标准(草案) [over.best.ics] (强调我的):
- 如果没有转换需要将参数与参数类型匹配,则隐式转换序列是由标识转换(13.3.3.1.1)组成的标准转换序列。
醇>
func(A())
不是身份,而是用户定义的。再次从标准 [[conv]] :
对于类类型,也考虑用户定义的转换;见12.3。通常,隐式转换序列(13.3.3.1)包含标准转换序列,后跟用户定义的转换,后跟另一个标准转换序列。
我认为您对标准转化存在误解。它们与用户定义的类型/类无关。标准转换仅适用于内置类型:左值到右值转换,数组到指针转换,函数到指针转换,整数提升,浮点提升,积分转换,浮点转换,浮点积分转换,指针转换,指向成员转换的指针,布尔转换和限定转换。 A
- &gt; int
不是这些中的任何一种,而是用户定义的转换。用户定义转换的标准, [[class.conv]] ,即12.3:
类对象的类型转换可以由构造函数和转换函数指定。这些转换称为用户定义的转换,用于隐式类型转换(第4节),初始化(8.5)和显式类型转换(5.4,5.2.9)。
您有两个具有相同等级的用户定义转换序列(请参阅M.M的答案以了解原因),因此编译器希望您消除歧义。