【问题标题】:A confusion about c++ function overloading关于 c++ 函数重载的困惑
【发布时间】:2012-06-03 00:04:59
【问题描述】:

我正在通过编译以下代码在 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;
}

任何解释为什么它是模棱两可的?提前谢谢。

【问题讨论】:

标签: c++ function overloading default arguments


【解决方案1】:

因为两个签名都匹配调用。

add();

可以解释为add(1,1)add()。当你写 void add(int a=1, int b=1) 时,你是在告诉编译器 - “听着,如果我在没有参数的情况下调用 add,我希望你将它们默认为 1

最重要的是,在不带参数地调用add() 时会发生什么?

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

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

【讨论】:

  • 所以,编译器在调用 add() 时会感到困惑,因为带有默认参数的函数的行为方式,它无法决定执行两个函数中的哪一个,对吧?
  • @pslayer89 你希望它表现如何?
  • 我没有预料到任何事情,我只是想弄清楚在这种情况下会发生什么以及背后的原因是什么。感谢您的解释。 :)
  • @pslayer89:一些谷歌研究会给你一个更快的答案! SO也不适合做你的私人研究助理。
  • 我在谷歌上找不到任何答案,因此我在这里发布了相关信息。很抱歉给您带来麻烦。
【解决方案2】:
void add(int a, int b);
void add();

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

您是否有理由需要为 ab 提供默认值?

【讨论】:

    【解决方案3】:

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

    1. 确定候选函数,
    2. 从候选函数中确定可行函数,
    3. 选择最佳可行函数。

    候选函数

    由于add 命名一个函数(而不是一个对象),第 13.3.1.1.1 节定义了如何确定候选函数。由于add 不合格(不包含.-&gt; 运算符),适用第3 条(取自C++11 的draft n3337):

    在不合格的函数调用中,名称不是由 -> 或 限定的。运算符,并且具有更一般的主表达式形式。按照函数调用中名称查找的常规规则 (3.4) 在函数调用的上下文中查找名称。通过该查找找到的函数声明构成候选函数集。由于名称查找的规则,候选函数集由 (1) 完全由非成员函数或 (2) 完全由某个类 T 的成员函数组成。在情况 (1) 中,参数列表与调用中的表达式列表。 [...]

    简而言之,候选函数是在函数调用上下文中通过标准名称查找找到的函数。名称查找在第 3.4 节中定义。通常,第 3.4.2 节(与参数相关的名称查找)会找到额外的候选函数,但所讨论的函数调用中没有参数,因此只有第 3.4.1 节很重要。特别是第 6 条:

    在函数的 declarator-id 之后的函数定义中使用的名称是命名空间 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&amp;) 的函数不能绑定到函数调用foo(0),因为non-const reference(例如int&amp;)不能绑定到右值(例如文字0)。但是,int foo(const int&amp;) 可以绑定到foo(0)

    最佳功能

    § 13.3.3 定义了一个函数在名称解析方面如何被认为比另一个函数“更好”:partial ordering 函数:

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

    由于没有参数,因此不能使用标准 1。 add()add(int,int) 都不是模板,因此 2 和 3 都不能使用。简而言之,没有一个功能比另一个更好。

    最后,§ 13.3.3 2 确定最终结果:

    如果恰好有一个可行函数比所有其他可行函数更好,那么它就是重载决议选择的那个;否则调用格式不正确。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-16
      • 2018-04-26
      • 2015-04-08
      • 2012-08-26
      • 1970-01-01
      • 1970-01-01
      • 2020-08-06
      • 1970-01-01
      相关资源
      最近更新 更多