簡體   English   中英

對重載函數錯誤的奇怪模棱兩可的調用

[英]Strange ambiguous call to overloaded function error

我想

void function(int y,int w)
{
    printf("int function");

}


void function(float y,float w)
{
    printf("float function");
}


int main()
{
    function(1.2,2.2);
    return 0;
}

我收到一個錯誤錯誤,如..

error C2668: 'function' : ambiguous call to overloaded function

當我嘗試調用function(1.2,2)function(1,2.2)它打印為“ int function

請說明什么時候會function(float y,float w)

查看來自 gcc 的錯誤信息:

a.cpp:16: error: call of overloaded ‘function(double, double)’ is ambiguous
a.cpp:3: note: candidates are: void function(int, int)
a.cpp:9: note:                 void function(float, float)

對任一函數的調用都需要截斷,這就是為什么兩者都不優於另一個的原因。 我懷疑你真的想要void function(double y,double w) 請記住,在C/C++ 中文字和參數傳遞默認浮點類型是 double ,而不是float

更新

如果您真的不想將函數簽名float更改為double ,您始終可以使用類型為float 的文字 如果將后綴f添加到浮點數,它們將被輸入為 float。

您的示例將是function(1.2f, 2f)function(1, 2.2f)

什么是運算符重載?

Sbi著名的Operator 重載常見問題解答非常詳細地回答了這個問題

為什么OP中允許存在兩個function版本?

請注意,它們采用不同的函數參數類型intfloat ),因此有資格作為有效的函數重載。

什么是重載決議?

它是由編譯器實現選擇最合適的函數/運算符的過程。 如果存在最佳可行函數並且是唯一的,則重載解析成功並產生它作為結果。 否則重載解析失敗並且調用被視為格式錯誤並且編譯器提供診斷。 編譯器使用隱式轉換序列來尋找最佳匹配函數。

C++03 標准 13.3.3.1 隱式轉換:

隱式轉換序列是用於將函數調用中的參數轉換為被調用函數的相應參數類型的轉換序列。

隱式轉換序列可以是以下類別之一:

  • 一個標准的轉換序列(13.3.3.1.1)
  • 用戶定義的轉換序列(13.3.3.1.2)
  • 省略號轉換序列(13.3.3.1.3)

請注意,對這些中的每一個進行排名以確定最佳可行功能。 最好的可行函數是其參數具有比所有其他可行函數更好或排名相同的隱式轉換序列的函數。標准在各自的部分中詳細說明了這些函數中的每一個。 標准轉換順序與這種情況有關,總結如下:

在此處輸入圖片說明

有足夠的背景重載決議。
讓我們檢查 OP 中的代碼示例:

function(1.2,2.2);

重要規則: 1.22.2是文字,它們被視為double數據類型。

在隱式轉換序列映射期間:
double類型的函數參數文字都需要轉換等級來調用floatint版本,並且沒有比其他更好的匹配,它們在轉換等級上的得分完全相同。 編譯器無法檢測到最佳可行匹配並報告歧義。

function(1.2,2);

在隱式轉換序列映射期間:
其中一個函數參數2int函數版本完全匹配,而另一個1.2具有轉換等級 對於將float作為參數的函數,兩個參數的隱式轉換序列都具有轉換等級
因此,采用int版本的函數比float版本得分更好,並且是最佳匹配並被調用。

如何解決重載歧義錯誤?

如果您不希望隱式轉換序列映射讓您失望,只需提供函數並以這樣的方式調用它們,以便參數完全匹配 由於精確匹配得分超過所有其他分數,因此您可以明確保證您想要的函數被調用。 在您的情況下,有兩種方法可以做到這一點:

解決方案1:

調用函數以便參數與可用函數完全匹配。

function(1.2f,2.2f);

由於1.2f2.2f被視為float類型,因此它們與float函數版本完全匹配。

解決方案2:

提供與被調用函數中的參數類型完全匹配的函數重載。

function(double, double){}

由於1.22.2被視為double被調用的函數與此重載完全匹配。

如果您不想(如已接受的答案中所述):

  • 使用浮點文字,例如1.2f
  • 或將現有的float重載更改為double

您可以添加另一個調用浮點重載的重載:

void function(double y, double w)
{
    function((float)y, (float)w);
}

現在main代碼將調用上述函數,該函數將調用float重載。

上面例子中的函數重載有不明確的調用,因為返回類型是相同的,並且函數調用中的第二個參數是 double,可以被視為 int 或 float,因此編譯器混淆了要執行的函數。

我希望這有助於此代碼對所有組合都是自我解釋的

您需要發送兩個浮點數才能調用浮點數函數

#include<iostream>
#include<stdio.h>

using namespace std;

//when arguments are both int
void function(int y,int w) {
    printf("int function\n");
}

//when arguments are both double
void function(double y, double w) {
    printf("double function\n");
}

//when arguments are both float
void function(float y, float w) {
    printf("float function\n");
}

//when arguments are int and float
void function(int y, float x) {
    printf("int float function\n");
}

//when arguments are float and int
void function(float y,int w) {
    printf("float int function\n");
}

//when arguments are int and double
void function(int y, double w) {
    printf("int double function\n");
}

//when arguments are double and int
void function(double y, int x) {
    printf("double int function\n");
}

//when arguments are double and float
void function(double y, float x) {
    printf("double float function\n");
}

//when arguments are float and double
void function(float y, double x) {
    printf("float double function\n");
}



int main(int argc, char *argv[]) {
    function(1.2,2.2);
    function(1.2f,2.2f);
    function(1,2);
    function(1.2,2.2f);
    function(1.2f,2.2);
    function(1,2.2);
    function(1,2.2f);
    function(1.2,2);
    function(1.2f,2);
    return 0;
}

將原始類型作為參數發送給函數時,如果您發送的原始類型與其請求的原始類型不完全相同,則應始終將其強制轉換為請求的原始類型。

int main()
{
    function(1.3f,                    2.4f);
    function(1.3f,                    static_cast<float>(2.4));
    function(static_cast<float>(1.3), static_cast<float>(2.4));
    function(static_cast<float>(1),   static_cast<float>(2));
    return 0;
}

默認情況下,十進制被視為雙精度。 如果您希望十進制為浮點數,請使用 f 后綴。 在您的示例中,當您調用 function(1.2,2.2) 時,編譯器會將您傳遞給它的值視為雙精度值,因此您在函數簽名中遇到了不匹配。

function(1.2,1.2) ====> function(double,double)

如果要保留函數簽名,則需要在傳遞浮點文字時使用浮點后綴。

function(1.2f,1.2f) ====>   function(float,float).

如果您對了解浮點文字更感興趣,可以參考

為什么在 MSVC 中默認情況下將浮點值(例如 3.14)視為雙精度值?

就像其他人所說的那樣,您為專為floats設計的重載函數提供了雙精度值 重載本身沒有任何錯誤。

這是重載函數的正確用法(注意數字后面的“f”):

function(1.0f, 2.0f);
function(1.2,2.2);

這些數字不是浮點數,而是雙數。 所以這段代碼說:

double p1 = 1.2;
double p2 = 2.2;
void (*fn)(double /*decltype(p1)*/, double /*decltype(p2)*/) = function;

編譯器現在正在尋找一個需要兩個雙精度的“函數”。 沒有完全匹配。 所以接下來它會尋找一個函數,它接受一個可以從雙精度轉換的參數。 有兩場比賽。

function(int, int);
function(float, float);

您有多種選擇。

  1. 添加精確匹配重載。

    void function(double, double) { printf("double function\\n"); }

  2. 使用鑄造。

    函數(static_cast(1.2),static_cast(2.2));

  3. 使用浮點數而不是雙精度數調用“函數”:

    功能(1.2f,2.2f);

嘗試這個

#include <iostream>
using namespace std;

void print(int i){
    cout << i << endl;
}

void print(float i){
    cout << i << endl;
}

int main(){
    print(5);
    print(5.5f);
    return 0;
}

在函數重載中,當 float 可能與其他同名函數中的其他數據類型沖突時,這可能是克服它的方法。 我試過了。

想象一下你的論點將如何通過。

如果它作為 1.2 和 2.2 傳遞給 (int,int) 函數,那么它將被截斷為 1 和 2。

如果它作為 1.2 和 2.2 傳遞給 (float,float) 它將按原樣處理。

所以這就是歧義蔓延的地方。

我找到了兩種方法來解決這個問題。 首先是文字的使用:-

int main()
{
        function(1.2F,2.2F);
    return 0;
}

其次,也是我喜歡這樣做的方式,它總是有效(也可以用於 C++ 的默認轉換和提升)。 對於整數:-

int main()
{
int a=1.2, b=2.2;
    function(a,b);
    return 0;
}

對於浮動:-

int main()
{
float a=1.2, b=2.2;
    function(a,b);
    return 0;
}

因此,而不是使用實際的 DIGITS。 最好先將它們聲明為類型,然后重載!

現在看看,如果你把它作為(1.2,2) or (1,2.2)發送,那么編譯器可以簡單地將它發送到 int 函數,它會工作。 但是,要將其發送到 float 函數,編譯器必須將 2 提升為 float。 僅在未找到匹配項時才會進行促銷。

參考:-計算機科學與 C++ Sumita Arora章節:函數重載

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM