关于C ++:对重载函数错误的奇怪歧义调用

Strange ambiguous call to overloaded function error

我正在努力

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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;
}

我收到类似的错误消息。

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

当我尝试调用function(1.2,2)function(1,2.2)时,它正在打印为" int函数"

请说明何时调用function(float y,float w)


查看来自gcc的错误消息:

1
2
3
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隐式转换:

An implicit conversion sequence is a sequence of conversions used to convert an argument in a function call to the type of the corresponding parameter of the function being called.

隐式转换序列可以是下列类别之一:

  • 标准转换顺序(13.3.3.1.1)
  • 用户定义的转换顺序(13.3.3.1.2)
  • 省略号转换序列(13.3.3.1.3)

请注意,对这些功能中的每一个进行排名,以确定最佳的可行功能。最好的可行函数是所有参数都具有比其他所有可行函数更好或相等等级的隐式转换序列的函数。标准在相应的部分中详细介绍了每个函数。标准转换顺序与此情况相关,总结为:

enter image description here

具有足够的超载分辨率背景。
让我们检查一下OP中的代码示例:

1
function(1.2,2.2);

重要规则:1.22.2是文字,它们被视为double数据类型。

在隐式转换序列映射期间:
带有double类型的两个函数参数文字都需要一个转换等级才能调用floatint版本,并且没有一个比另一个更好的匹配方式,它们在转换等级上得分完全相同。编译器无法检测到最佳可行匹配,并且报告了歧义。

1
function(1.2,2);

在隐式转换序列映射期间:
函数参数2之一与int函数版本完全匹配,而另一个1.2具有转换等级。对于以float作为参数的函数,两个参数的隐式转换序列具有转换等级。
因此,采用int版本的函数得分要优于float版本,并且是最佳匹配并被调用。

如何解决超载歧义错误?

如果您不希望隐式转换序列映射让您失望,只需提供函数并以某种方式调用它们,以使参数完全匹配。由于精确匹配的得分高于其他所有得分,因此您可以肯定地调用所需函数。在您的情况下,有两种方法可以执行此操作:

解决方案1:

Call the function so that parameters are exact match to the functions available.

1
function(1.2f,2.2f);

由于1.2f2.2f被视为float类型,因此它们与float函数版本完全匹配。

解决方案2:

Provide a function overload which exactly matches the parameter type in called function.

1
function(double, double){}

由于1.22.2被视为double,因此调用的函数与此重载完全匹配。


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

  • 使用浮点文字,例如1.2f
  • 或将现有的float重载更改为double

您可以添加另一个重载,该重载调用浮点数:

1
2
3
4
void function(double y, double w)
{
    function((float)y, (float)w);
}

现在,您在main中的代码将调用上面的函数,该函数将调用float重载。


上面示例中的函数重载具有歧义的调用,因为返回类型相同,并且函数调用中的第二个参数为double,可以将其视为int或float,因此编译器会混淆执行哪个函数。


我希望这个帮助
该代码是所有组合的自我解释

您需要发送两个float才能调用float函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include<iostream>
#include<stdio.h>

using namespace std;

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

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

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

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

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

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

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

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

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



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


默认情况下,十进制被视为双精度。如果希望十进制为浮点数,请在后缀f后面加上。
在您的示例中,当您调用function(1.2,2.2)时,编译器会将传递给它的值视为double值,因此函数签名不匹配。

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

如果要保留函数签名,则在传递浮点字面量时需要使用浮点后缀。

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

如果您更想了解浮点文字,可以参考

为什么在MSVC中默认将3.14之类的浮点值视为double?


将原始类型作为参数发送给函数时,如果要发送的原始类型与请求的原始类型不完全相同,则应始终将其强制转换为请求的原始类型。

1
2
3
4
5
6
7
8
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'):

1
function(1.0f, 2.0f);

尝试这个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#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
function(1.2,2.2);

这些数字不是浮点数,而是双精度数。所以这段代码说:

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

编译器现在正在寻找一个需要两次加倍的"函数"。没有完全匹配的内容。因此,接下来,它寻找一个函数,该函数带有可以从双精度类型强制转换的参数。有两场比赛。

1
2
function(int, int);
function(float, float);

您有几种选择。

  • 添加完全匹配重载。

    虚函数(double,double)
    {
    printf(" double function n");
    }

  • 使用铸造。

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

  • 用浮点数而不是双精度数来调用"函数":

    函数(1.2f,2.2f);


  • 试想一下您的论点将如何通过。

    如果将其作为1.2和2.2传递给(int,int)函数,则它将被截断为1和2。

    如果将其作为1.2和2.2传递给(float,float),则将按原样进行处理。

    这就是歧义蔓延的地方。

    我发现了两种解决此问题的方法。
    首先是文字的使用:

    1
    2
    3
    4
    5
    int main()
    {
            function(1.2F,2.2F);
        return 0;
    }

    其次,也是我喜欢的方式,它始终有效(也可以用于C ++的默认转换和升级)。
    对于int:

    1
    2
    3
    4
    5
    6
    int main()
    {
    int a=1.2, b=2.2;
        function(a,b);
        return 0;
    }

    对于浮动:

    1
    2
    3
    4
    5
    6
    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 ++的计算机科学
    住田Arora
    章节:函数重载