为什么这些重载函数调用不明确?

时间:2012-08-09 09:41:58

标签: c++ implicit-conversion overload-resolution

为什么以下重载函数调用不明确?编译错误:

  

调用重载'test(long int)'是模糊的,候选者是:void test(A)|   无效测试(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 个答案:

答案 0 :(得分:6)

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

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

这些排名如何?标准在 13.3.3.2中对隐式转换序列进行排名[over.ics.rank]

  

标准转换序列S1是比转换序列更好的转换序列   标准转换序列S2,如果S1是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()

答案 1 :(得分:1)

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

答案 2 :(得分:1)

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

没有测试(长)。

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

要调用测试(A),它的转换序列为long - > int - >甲

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

根据标准的排名规则,如果一个排名比另一个排名更好,它将选择一个 - 或者它会因模糊而失败。

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

标准中有很多关于如何计算转换序列排名的规则 13.3.3最佳可行功能

答案 3 :(得分:0)

试试这个:

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

关键字显式停止编译器进行隐式转换。

答案 4 :(得分:0)

允许编译器只对用户类型进行一次隐式转换。如果这也涉及原始类型之间的转换,则它们不计算在内。即使您在test(B)的情况下有两个转换,但以下内容无法编译:

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

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

void test(const A&) {}

....

test(5);

要禁用编译器进行隐式转换,您应该使用explicit关键字和构造函数