过载分辨率和用户定义的转换

时间:2015-12-28 08:42:23

标签: c++ overload-resolution

考虑简单的代码:

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)会调用,但调用仍然不明确。

所以,请帮助我,我错了,为什么电话不明确。非常感谢:)

2 个答案:

答案 0 :(得分:6)

此处的两个转换序列A -> BA -> int都是用户定义的,因为它们是通过您定义的函数运行的。

用户定义的转换序列排序规则见13.3.3.2(N3797):

  

用户定义的转换序列U1是一个比另一个用户定义的转换序列U2更好的转换序列,如果它们包含相同的用户定义转换函数或构造函数,或者它们初始化相同的类聚合初始化,在任何一种情况下,U1的第二个标准转换序列优于U2的第二个标准转换序列

这两个转换序列不包含相同的用户定义转换函数,并且它们不会在聚合初始化中初始化相同的类(因为一个初始化int)。

因此,一个序列排在另一个序列之上并不是真的,因此这个代码是不明确的。

答案 1 :(得分:3)

  

所以序列是 - &gt; A() - &gt; B :: B(常数A&amp;) - &gt;标准转换(身份转换)

没有!摘自标准(草案) [over.best.ics] (强调我的):

  
      
  1. 如果没有转换需要将参数与参数类型匹配,则隐式转换序列是由标识转换(13.3.3.1.1)组成的标准转换序列。
  2.   

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的答案以了解原因),因此编译器希望您消除歧义。