繁体   English   中英

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

为什么它是模棱两可的? 提前谢谢。

因为两个签名都与呼叫匹配。

add();

可以解释为add(1,1)add() 当您编写void add(int a=1, int b=1) ,您会告诉编译器- “听伙计,如果我调用不带参数的add ,我希望您将它们默认设置为1

最重要的是, 能指望什么发生,当你调用add()不带参数?

  • 如果您希望它打印2 ,请删除不带参数的版本。

  • 如果您希望它打印4 ,请从第一个版本中删除默认参数。

void add(int a, int b);
void add();

您不应提供ab默认值。 使用默认值时,编译器无法知道对add()的调用应使用第一个函数还是第二个函数。

您是否有理由要给ab默认值?

重载分辨率由C ++标准的第13.3节(至少C ++ 03C ++ 11 )定义。 分为三个部分:

  1. 确定候选功能,
  2. 从候选功能中确定可行的功能,
  3. 选择最佳可行的功能。

候选功能

由于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条:

that is a member of namespace N (where, only for the purpose of exposition, N could represent the global scope) shall be declared before its use in the block in which it is used or in one of its enclosing blocks (6.3) or, shall be declared before its use in namespace N or, if N is a nested namespace, shall be declared before its use in one of N's enclosing namespaces. 在函数的之后的函数定义中使用的名称是名称空间N的成员(其中,仅出于说明目的,N可以表示全局范围)应在该名称在块中使用之前声明:它已被使用或在其封闭的块(6.3)中使用,或者应在其在命名空间N中使用之前声明;或者,如果N是嵌套的命名空间,则应在其在N的封闭名称空间之一中使用之前声明。

简而言之,将搜索当前名称空间和任何父名称空间,并且仅考虑已经声明的功能。 在示例代码中,在全局名称空间中在main之前声明的任何带有add名称的函数都是候选函数: add(int, int)add() 如果要在main之后声明(例如)函数add(float, float) ,则它不是候选函数。

可行的功能

第13.3.2节:

2首先,要成为可行的功能,候选功能应具有足够的参数,以在数量上与列表中的参数一致。
  • 如果列表中有m个参数,则所有具有m个参数的候选函数都是可行的。
  • 参数少于m个的候选函数只有在其参数列表(8.3.5)中带有省略号时才可行。 为了重载解析,任何没有相应参数的参数都被视为“与省略号匹配”(13.3.3.1.3)。
  • 仅当(m + 1)-st参数具有默认参数(8.3.6)时,具有超过m个参数的候选函数才可行。 为了解决过载,参数列表在右侧被截断了,因此恰好有m个参数。
3其次,为了使F成为可行的函数,每个参数都应存在一个隐式转换序列 (13.3.3.1),该序列将其转换为F的相应参数。如果该参数具有引用类型,则隐式转换序列包括绑定引用的操作,以及对非const的左值引用不能绑定到右值,右值引用不能绑定到左值的事实会影响该函数的可行性(请参见13.3.3.1.4)。

参数列表有0个参数。 add()有0个参数,因此是可行的。 add(int, int)有2个参数,但是第一个具有默认参数,因此可行。 由于调用中没有参数,因此第3节中的转换不会起作用,但是了解该子句很重要,特别是因为它指出声明为int foo(int&)函数不能绑定到函数调用foo(0) ,因为非常量引用 (例如int& )不能绑定到右值(例如文字0)。 但是,可以将int foo(const int&)绑定到foo(0)

最佳功能

第13.3.3节定义了在名称解析方面,按功能的部分排序 ,一个功能如何被认为比另一个功能“更好”:

  1. 某些转换比其他转换“更好”(第13.3.3.2节),并且使用更好的参数转换的函数是更好的函数。
  2. 如果1不能确定更好的功能,则非模板功能要好于模板功能。
  3. 如果2不能确定更好的功能,则功能模板的专业化要比另一个更好。(“更专业”是第14.5.6.2节中定义的部分排序)。

由于没有参数,因此无法使用条件1。 add()add(int,int)都不是模板,因此不能使用2或3。 简而言之,两种功能都不比另一种更好。

最后,第13.3.3 2节确定最终结果:

如果恰好有一个可行的功能比所有其他可行的功能要好,则它是由过载解决方案选择的; 否则,通话格式不正确。

由于示例代码中有两个可行的函数,因此该调用格式不正确。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM