我认为在重载期间,编译器会检查形式参数是否属于同一类型。例如:
void a(int x)
void a(double x)
可以仅仅因为两个“x”具有不同的类型而重载。
但是,以下两个有不同的类型吗?
void f(int y)
void f(int& y)
我知道一个是 PBV,另一个是 PBR。但是第二个 y 也有“int”类型,对吧?为什么编译成功?
PS我注意到虽然它编译了,但它没有运行,报告运行时不明确的错误。
我认为在重载期间,编译器会检查形式参数是否属于同一类型。例如:
void a(int x)
void a(double x)
可以仅仅因为两个“x”具有不同的类型而重载。
但是,以下两个有不同的类型吗?
void f(int y)
void f(int& y)
我知道一个是 PBV,另一个是 PBR。但是第二个 y 也有“int”类型,对吧?为什么编译成功?
PS我注意到虽然它编译了,但它没有运行,报告运行时不明确的错误。
从广义上讲,函数可以在以下基础上重载:
该示例可以编译,因为它满足第二个条件。
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;
}
以上将导致编译器产生歧义,因为编译器无法检测到两个函数调用之间的最佳匹配。
让我们调用 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 &)' 形成一个重载集。
首先,歧义总是在编译时报告。
其次,您的示例是否编译取决于您如何使用此功能
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
形式都可以这样调用。