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

hu *_*ang 1 c++ overload-resolution implicit-conversion

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

调用重载'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;
}
Run Code Online (Sandbox Code Playgroud)

Tem*_*Rex 6

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

test(0L)与任何重载都不完全匹配,因为没有过载test(long).您提供的两个重载都在其参数上具有用户定义的转换,但编译器认为它们同样可行.所述A过载必须做一个标准转换(长为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;
}
Run Code Online (Sandbox Code Playgroud)

注意:int main()不是void main().