13

我认为在重载期间,编译器会检查形式参数是否属于同一类型。例如:

void a(int x)
void a(double x)

可以仅仅因为两个“x”具有不同的类型而重载。

但是,以下两个有不同的类型吗?

void f(int y)
void f(int& y)

我知道一个是 PBV,另一个是 PBR。但是第二个 y 也有“int”类型,对吧?为什么编译成功?

PS我注意到虽然它编译了,但它没有运行,报告运行时不明确的错误。

4

4 回答 4

8

从广义上讲,函数可以在以下基础上重载:

  • 参数数量
  • 参数类型
  • 论证顺序

该示例可以编译,因为它满足第二个条件。
int并且int &是不同的数据类型


考虑以下示例:

void foo(int i);
void foo(int& i);
void foo(int i){}
void foo(int& i){}
int main()
{
     return 0;
}  

上面的代码可以编译,因为它是有效代码。根据传递给函数的函数参数,编译器可能/可能不会检测到函数调用的最佳匹配。因此,函数本身可以共存,但它们在某些方面的使用可能会导致编译器产生歧义。

例如:在以下代码中,文字不能绑定到非常量引用,因此函数调用的唯一候选者是非引用版本,这应该可以编译并正常工作:

void foo(int i);
void foo(int& i);
void foo(int i){}
void foo(int& i){}
int main()
{
    foo(20); 
    return 0;
}  

但,

void foo(int i);
void foo(int& i);
void foo(int i){}
void foo(int& i){}
int main()
{
    int i = 10;
    foo(i);
    return 0;
}  

以上将导致编译器产生歧义,因为编译器无法检测到两个函数调用之间的最佳匹配。

于 2012-12-10T10:19:04.677 回答
2

让我们调用 f(x),其中 x 是一个 int。

$13.3.3.1.4 - “当引用类型的参数直接绑定(8.5.3)到参数表达式时,隐式转换序列是恒等转换,除非参数表达式的类型是参数类型的派生类,在这种情况下,隐式转换序列是派生到基转换"

因此 f(int &) 是完全匹配的,f(int) 也是如此,因为两者都是身份转换。因此模棱两可

现在让我们接听电话'f(2)'

这很好,因为 'f(int &)' 根本不匹配,因为右值不绑定到非 const 左值。因此,没有歧义

因此,该标准允许 'f(T)' abd 'f(T &)' 形成一个重载集。

于 2012-12-10T10:30:30.580 回答
2

首先,歧义总是在编译时报告。

其次,您的示例是否编译取决于您如何使用此功能

void f(int y)
{
}
void f(int& y)
{
}


int main ()
{
    int a = 10;

    f (a); // ERROR: ambiguous call
    f (10); // OK
}

在第一种情况下有一个错误,因为a可以作为副本和引用传递。在第二种情况下不会出错,因为int字面量不能通过非常量引用传递

于 2012-12-10T10:26:57.313 回答
2

那要看。如果您不从代码中调用这些函数,编译器可能会将它们优化掉。如果没有,您可以使用文本查看器打开 .obj 文件并搜索函数名称(给它一个比 更唯一的名称f,例如floop:-)),您将看到两个使用您的基本函数名称的名称。

但是,如果您确实尝试使用它们,那么您会注意到不同之处。如果你打电话

f(5);

编译器只能使用f(int y)版本,因为不可能通过引用传递常量。但如果你这样做

int b = 10;
f(b);

然后编译器会发出一个混淆错误,因为这两种f形式都可以这样调用。

于 2012-12-10T10:27:02.597 回答