关于c++函数重载的困惑
A confusion about c++ function overloading
我通过编译以下代码来尝试c++中的默认参数值和函数重载,结果让我感到惊讶:
Line 19: error: call of overloaded 'add()' is ambiguous
我编译的代码是:
#include <iostream>
using namespace std;
void add(int a=1, int b=1){
cout<<a+b;
}
void add(){
int a =2, b=2;
cout<<a+b;
}
int main(){
add();
return 0;
}
有什么解释为什么它模棱两可吗?提前Thx。
因为两个签名都与调用匹配。
add();
可以被解释为CCD_ 1或CCD_。当你编写void add(int a=1, int b=1)
时,你告诉编译器-"听着,伙计,如果我在没有参数的情况下调用add
,我希望你将它们默认为1
">
最重要的是,当您在没有参数的情况下调用add()
时,YOU期望发生什么?
如果希望打印
2
,请删除不带参数的版本。如果希望打印
4
,请从第一个版本中删除默认参数。
void add(int a, int b);
void add();
不应为a
和add(1,1)
0指定默认值。对于默认值,编译器无法知道对add()
的调用应该使用第一个函数还是第二个函数。
您是否需要为a
和b
提供默认值?
过载分辨率由C++标准的§13.3定义(至少是C++03和C++11)。有三个部分:
- 确定候选函数
- 从候选函数中确定可行函数
- 选择最佳可行函数
候选函数
由于add
命名了一个函数(而不是对象),§13.3.1.1.1定义了如何确定候选函数。由于add
不合格(不包含.
或->
运算符),第3条适用(取自C++11的草案n3337):
在非限定函数调用中,名称不是由->或限定的。运算符,并具有更通用的主表达式形式。根据函数调用中名称查找的正常规则(3.4),在函数调用的上下文中查找名称。通过查找找到的函数声明构成候选函数集。由于名称查找的规则,候选函数集由(1)完全由非成员函数组成,或(2)完全由某个类T的成员函数组成。在情况(1)中,参数列表与调用中的表达式列表相同。[…]
简而言之,候选函数是在函数调用的上下文中通过标准名称查找找到的函数。名称查找在§3.4中有定义。通常,§3.4.2(依赖于参数的名称查找)会找到其他候选函数,但有问题的函数调用中没有参数,因此只有§3.4.1。特别是,第6条:
在函数的声明符id之后的函数定义中使用的名称是命名空间N的成员(其中,仅为了说明的目的,N可以表示全局范围),应在其在其中使用的块或其一个封闭块(6.3)中使用之前声明,如果N是嵌套的名称空间,则应在其在N的一个封闭名称空间中使用之前声明。
简而言之,将搜索当前命名空间和任何父命名空间,并且只考虑已声明的函数。在示例代码中,在名称为add
的全局命名空间中,在main
之前声明的任何函数都是候选函数:add()
0和add()
。如果在main
之后声明(例如)函数add(float, float)
,它就不是候选函数。
可行函数
§13.3.2:
2首先,要成为一个可行的函数,候选函数应该有足够的参数,以便在数量上与列表中的参数一致。3其次,对于F是一个可行函数,每个参数都应存在一个隐式转换序列(13.3.3.1),该序列将该参数转换为F的相应参数。如果该参数具有引用类型,则隐式转换顺序包括绑定引用的操作,对非常量的左值引用不能绑定到右值,右值引用不能链接到左值,这可能会影响函数的可行性(见13.3.3.1.4)。
- 如果列表中有m个参数,则所有具有恰好m个参数的候选函数都是可行的
- 参数少于m的候选函数只有在其参数列表中有省略号时才可行(8.3.5)。为了解决过载问题,任何没有相应参数的参数都被视为"匹配省略号"(13.3.3.1.3)
- 只有当(m+1)-st参数具有默认参数(8.3.6)时,具有m个以上参数的候选函数才是可行的。为了解决过载问题,参数列表在右侧被截断,因此正好有m个参数
参数列表有0个参数。add()
有0个参数,因此它是可行的。add(int, int)
有两个参数,但第一个有一个默认参数,所以它是可行的。由于调用中没有参数,所以子句3中的转换不会起作用,但了解该子句很重要,尤其是当它指出声明为int foo(int&)
的函数不能绑定到函数调用foo(0)
时,因为非常量引用(例如int&
)不能绑定到右值(例如文字0)。然而,int foo(const int&)
可以与foo(0)
结合。
最佳功能
§13.3.3定义了在函数偏序的名称解析方面,一个函数如何被认为比另一个"更好":
- 有些转换比其他转换"更好"(§13.3.3.2),使用更好参数转换的函数是更好的函数
- 如果1不能确定更好的函数,那么非模板函数比模板函数更好
- 如果2不能确定更好的函数,那么比另一个更专业化的函数模板专业化更好("更专业化"是§14.5.6.2中定义的偏序)
由于没有参数,因此不能使用条件1。add()
和add(int,int)
都不是模板,因此2和3都不能使用。简而言之,两种功能都不如另一种。
最后,§13.3.3 2确定了最终结果:
如果恰好有一个可行函数比所有其他可行函数都好,那么它就是通过过载解析选择的函数;否则该调用是格式错误的
由于示例代码中有两个可行的函数,因此调用格式不正确。
- 继承函数的重载解析
- 你能重载对象变量名本身返回的内容吗
- 从父命名空间重载类型
- 使用C++中的模板和运算符重载执行矩阵运算
- 为什么这个运算符<重载函数对 STL 算法不可见?
- 重载操作程序时出错>>用于类中的字符串 memebr
- 一个关于在C++中重载布尔运算符的问题
- 不同翻译单元中不可重载的非内联函数定义
- 为什么使用SFINAE而不是函数重载
- 为什么我不能在 C++ 中的特定函数重载中调用同一函数的任何其他重载?
- 将重载的成员函数传递给函数模板
- c++:可变模板和函数重载
- 重载元组索引运算符-C++
- 如何使用重载的相等(==)运算符向测试用例添加描述
- 重载==不适用于二进制树
- 为什么Mat类的两个对象可以在不重载运算符+的情况下添加
- 重载运算符new[]的行为取决于析构函数
- 正在尝试重载二进制搜索树分配运算符
- 重载Singly Linked List中的赋值运算符
- 取消引用运算符不能重载