对重载函数错误的奇怪模棱两可的调用

Posted

技术标签:

【中文标题】对重载函数错误的奇怪模棱两可的调用【英文标题】:Strange ambiguous call to overloaded function error 【发布时间】:2021-12-04 12:35:48 【问题描述】:

我在努力

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)

【问题讨论】:

您正在将doubles 传递给函数,并且没有任何重载更好。尝试传递浮点数,例如1.2f. 我看到你在这个问题上开了一个赏金。 L Lawliet 的回答没有充分解释或解决什么问题?考虑editing 您的问题以提及您的其他问题。 问题得到了完美的回答。还有什么好说的? Bjarne Stroustrup 应该亲自回答吗?不会发生的。 也许他只是想要另一个或用另一个比 L Lawliet 的答案更容易的解释来改进答案..!有可能.. @nightStalkEr 如果您对如何使 L Lawliet 的回答更清楚有任何想法,请不要自己保密。它已经尽可能清晰了! 【参考方案1】:

查看来自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,您可以随时使用 literals 类型为 float。如果您将后缀 f 添加到 浮点数,它们将被键入 float。

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

【讨论】:

我将赏金给 l lawliet,因为下面没有其他答案可以给我这样的明确意见。 如果重载函数不存在,我们会收到警告“隐式常量转换中的溢出”如果我们传递整数代替 char”。但如果存在任何其他重载函数,我们会收到错误。示例:如果在没有其他重载函数存在时将值 1000 传递给函数 func1(char c),我只会收到警告。但是当我添加另一个函数,如 func1(float f) 时,相同的函数调用抛出错误(重载函数的调用不明确)。我想了解这是怎么发生的。【参考方案2】:

什么是运算符重载?

Sbi's Famous Operator overloading faq 非常详细地回答了这个问题。

为什么允许OP中的两个function版本存在?

请注意,它们采用不同的函数参数类型intfloat),因此符合有效的函数重载。

什么是重载解析?

这是编译器实现选择最合适的函数/运算符的过程。如果存在最佳可行函数并且是唯一的,则重载解析成功并生成它作为结果。否则重载解析失败,调用被视为格式错误,编译器提供诊断。编译器使用implicit conversion sequence 来查找最佳匹配函数。

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,因此调用的函数与此重载完全匹配。

【讨论】:

【参考方案3】:

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

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

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

void function(double y, double w)

    function((float)y, (float)w);

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

【讨论】:

【参考方案4】:

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

【讨论】:

返回类型与它无关。【参考方案5】:

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

你需要发送两个float来调用一个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;

【讨论】:

这可能是我见过的最详细的函数重载演示了... 我已经这样回答了,以便为这个特定类型清除所有混淆【参考方案6】:

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

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;

【讨论】:

这种说法完全不真实。该语言具有适用于几乎所有情况的扩展规则。它们不适用于这一点,这就是问题所在。 -1【参考方案7】:

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

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

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

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

如果您有兴趣了解浮点文字,可以参考

Why floating point value such as 3.14 are considered as double by default in MSVC?

【讨论】:

【参考方案8】:

正如其他人所说,您将 doubles 赋予为 floats 设计的重载函数。重载本身没有任何错误。

这是重载函数的正确用法(注意数字后面的“f”):

function(1.0f, 2.0f);

【讨论】:

【参考方案9】:
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);

您有多种选择。

    添加完全匹配重载。

    无效函数(双,双) printf("双重函数\n");

    使用强制转换。

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

    用浮点数而不是双精度数调用“函数”:

    函数(1.2f, 2.2f);

【讨论】:

【参考方案10】:

试试这个

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

在函数重载中,当浮点数可能与其他同名函数中的其他数据类型冲突时,这可能是克服它的方法。我试过了。

【讨论】:

【参考方案11】:

想象一下你的论点将如何传递。

如果将其作为 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:-

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;

所以不要使用实际的数字。最好先将它们声明为类型,然后重载!

现在看,如果你把它作为(1.2,2) or (1,2.2) 发送,那么编译器可以简单地将它发送到 int 函数,它就可以工作了。 但是,要将其发送到 float 函数,编译器必须将 2 提升为 float。只有在没有找到匹配项时才会进行促销。

参考:- C++ 计算机科学 住田阿罗拉 章节:函数重载

【讨论】:

如果它作为 1.2 和 2.2 传递给 (float,float) 它将按原样处理。它将略微四舍五入。 (浮点数不好玩吗?) “这里”不是“歧义蔓延的地方”。如果将参数指定为浮点数,则不会有歧义。产生歧义是因为参数是 doubles,并且没有首选的转换选择。 -1

以上是关于对重载函数错误的奇怪模棱两可的调用的主要内容,如果未能解决你的问题,请参考以下文章

避免在人为的模棱两可的重载函数调用中拼写出类型

使用 + (unary plus) 为 lambda 解决函数指针和 std::function 上的模棱两可的重载

“运算符”的 C++ 模棱两可的重载

C++ 编译器错误:对重载函数的模糊调用

VC++2010 中的编译器错误(2008 年干净!),“对重载函数的模糊调用”

错误 C2668 从站点 http://h264bitstream.sourceforge.net/ 对重载函数代码的模糊调用