簡體   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