1

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

重载 '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;
}
4

5 回答 5

6

你得到了一个错误,因为重载解析必须从两个同样可行的函数中进行选择(两者都有用户定义的转换)。函数重载解析是一个非常复杂的主题。有关重载解决方案的更多详细信息,请参见Stephan T. Lavavej最近的讲座。通常最好制作单参数构造函数explicit,然后使用显式构造函数参数调用您的函数。

test(0L)与任何重载都不完全匹配,因为没有重载test(long)。您提供的两个重载都对其参数进行了用户定义的转换,但编译器认为它们同样可行。重载必须执行A标准转换(long 到 int),然后是用户定义的转换(int 到 A),B重载是用户定义的转换(long 到 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()

于 2012-08-09T09:47:20.480 回答
1

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

于 2012-08-09T09:49:20.883 回答
1

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

没有测试(长)。

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

要调用 test(A),它有一个 long -> int -> A 的转换序列。

调用 test(B) 它有一个 long -> B 的转换序列。

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

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

标准中有一长串关于如何计算转换序列排名的规则在第13.3.3 节“最佳可行函数”中

于 2012-08-09T09:54:28.953 回答
0

试试这个:

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

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

于 2012-08-09T09:47:42.290 回答
0

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

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

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

void test(const A&) {}

....

test(5);

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

于 2012-08-09T10:07:36.063 回答