为什么编译器可以通过引用传递和值传递来重载函数

Why the compiler can overload functions with passing by reference and passing by value

本文关键字:值传 重载 函数 为什么 可以通过 引用 编译器      更新时间:2023-10-16

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

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

可以重载,因为两个"x"具有不同的类型。

但是,以下两种类型不同吗?

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

我知道一个是PBV,另一个是PBSR。但是第二个y的类型也是"int",对吧?为什么它编译成功?

p.S。我注意到,尽管它进行了编译,但它并没有运行,报告了运行时的模糊错误。

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

  • 参数数
  • 参数的类型
  • 自变量的顺序

编译该示例是因为它满足第二个条件
intint &是不同的数据类型


考虑以下示例:

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;
}  

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

首先,总是在编译时报告模糊性。

其次,你的例子是否编译取决于你如何使用这个函数

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

int main ()
{
int a = 10;
f (a); // ERROR: ambiguous call
f (10); // OK
}

在第一种情况下会出现错误,因为a可以作为副本和引用传递。在第二种情况下,将不会出现错误,因为int文字无法通过非常量引用传递

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

但如果你真的尝试使用它们,那么你会注意到不同。如果你打电话给

f(5);

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

int b = 10;
f(b);

然后编译器将发出一个友好错误,因为两个f形式都可以用这种方式调用。

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

$13.3.3.1.4-"当引用类型的参数直接绑定时(8.5.3)对于自变量表达式,隐式转换序列为标识转换,除非参数表达式具有类型是参数类型的派生类,在这种情况下隐式转换序列是一种派生到基的转换">

因此f(int&)是一个精确匹配,f(int)也是,因为两者都是身份转换。因此,模糊

现在让我们接电话"f(2)">

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

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