2012-08-09 112 views
1

为什么下面的重载函数调用模糊?随着编译错误:为什么这些重载的函数调用不明确?

call of overloaded 'test(long int)' is ambiguous,candidates are: void test(A)| void test(B)|

代码:

class A 
{ 
    public: 
     A(int){} 
     A(){} 
}; 

class B: public A 
{ 
    public: 
     B(long){} 
     B(){} 
}; 

void test(A a) 
{ 
} 

void test(B b) 
{ 
} 

void main() 
{ 
    test(0L); 
    return; 
} 

回答

5

因为重载具有两个同样可行函数(既具有用户定义的转换)选择您得到一个错误。函数重载解析是一个非常复杂的主题。有关过载分辨率的更多详细信息,请参阅Stephan T. Lavavej的recent lecture。通常最好使用单参数构造函数explicit,然后使用显式构造函数参数调用您的函数。

test(0L)与任何过载都不完全匹配,因为没有过载test(long)。您提供的两个重载都在其参数上有用户定义的转换,但编译器认为它们同样可行。 A过载必须执行标准转换(long转换为int),后跟用户定义的转换(int转换为A),并且B将用户定义的转换(long转换为B)进行重载。但都是隐式用户定义的转换序列

这些排名如何?标准说在13.3.3.2排名的隐式转换的序列[over.ics.rank]

Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if S1 is a proper subsequence of S2

这些类型的例如平局决胜如果A是B的派生类(反之亦然),则适用。但是在这里,两个转换序列都不是另一个的后续序列。因此它们同样可行并且编译器无法解决呼叫。

class A 
{ 
public: 
    explicit A(int){} 
    A(){} 
}; 

class B: public A 
{ 
public: 
    explicit B(long){} 
    B(){} 
}; 

void test(A a) 
{} 

void test(B b) 
{} 

int main() 
{ 
    test(A(0L)); // call first overload 
    test(B(0L)); // call second overload 
    return 0; 
} 

注:这是int main(),不void main()

+0

+1,这是最正式的正确答案,但你可以扩大解释了一下。 – Xeo 2012-08-09 09:51:30

+0

@rhalbersma:但我认为测试(0L)更准确地匹配测试(B b)?为什么不明确? – 2012-08-09 09:54:53

+0

'0L'是'long',所以你的第二段应该说“没有'test(long)'”。 – Xeo 2012-08-09 10:01:20

0

试试这个:

class A 
{ 
    public: 
    explicit A(int){} 
    A(){} 
}; 

关键字明确停止编译器做隐式转换。

1

函数重载考虑确切的参数类型或隐式转换。 在您的示例中,从重载的角度来看,备选方案A(0L)和B(0L)都是相同的,因为需要隐式构造函数调用。

1

您正在使用long类型的参数调用测试。

没有测试(长)。

编译器必须在测试(A)和测试(B)之间进行选择。

为了调用测试(A)它具有长转换序列 - > INT - > A.

为了调用测试(B)它具有长转换序列 - > B.

根据在标准的排名规则中,如果一个排名比另一个排名靠前,那么它将选择一个排名规则 - 否则它会以模糊不清的方式失败。

在这个特定情况下,两个转换序列的排列是相同的。

还有就是在标准规定它是如何计算转换序列的部分排名一长串13.3.3最佳可行函数”

+0

和规则在哪里? – 2012-08-09 09:57:11

+0

在标准中。生病了,请继续看。 – 2012-08-09 09:57:36

+0

但它并不解释为什么不搜索最近的潜在转换树。 – 2012-08-09 10:07:50

0

编译器允许这样做只有一个隐式转换到用户类型如果这还涉及到基本类型之间的转换,他们不指望即使你在test(B)情况下,你拥有两个转换,但下面不会编译:

class B 
{ 
public: 
    B(int) {} 
}; 

class A 
{ 
public: 
    A(const B&) {} 
}; 

void test(const A&) {} 

.... 

test(5); 

要禁用编译器做你的隐式转换应该使用explicit关键字与构造

相关问题