为啥在传递 long long 时调用具有两个 double 类型参数的重载函数?

Posted

技术标签:

【中文标题】为啥在传递 long long 时调用具有两个 double 类型参数的重载函数?【英文标题】:Why is an overloaded function with two arguments of type double called when passing a long long?为什么在传递 long long 时调用具有两个 double 类型参数的重载函数? 【发布时间】:2020-09-21 09:17:01 【问题描述】:

我写了这两个重载:

int func(int, int) 
    return 1;


int func(double, double) 
    return 2;

当我用明显的两个调用方案调用它们时,即func(1, 1)func(1.0, 1.0),分别调用了第一个和第二个重载函数,当我尝试调用func(1, 1.0) 时,它给了我一个错误,但是当我将1 转换为long long 时,我没有收到错误,并且第二个重载是调用的那个。

#include <iostream>
int main()

    std::cout << func(1, 1); // outputs 1.
    std::cout << func(1.0, 1.0); // outputs 2.
    // std::cout << func(1, 1.0); // erroneous.
    std::cout << func((long long)1, 1.0); // outputs 2.

为什么会这样?起初,我认为这是因为一些促销活动,但我尝试了第三次使用两个浮点数的重载,但我无法通过像 func((int)1, 1.0f) 那样调用它来调用它。不知道为什么不一样,也不知道为什么在传递long long时调用了第二个重载。

【问题讨论】:

基于提供的参数的最佳匹配。 long long 的字节大小与双倍相同或更接近,具体取决于您的操作系统。在任何情况下,第二个参数已经匹配一个双精度。 @stackoverblast 我不认为是这种情况,但也许我错了。正如我在上一段中所说,我尝试对浮点数做同样的事情(传递一个 int,这在我的机器上是相同的大小)但它没有工作。 无关:这是另一个值得关注的分辨率难题:String literal matches bool overload instead of std::string @stackoverblast 字节大小等不要进入这个 【参考方案1】:

选择调用重载集中的哪个函数(即overload resolution)取决于(部分)函数调用的多少参数必须通过implicit conversion,以及需要什么样的转换。

与您的示例相关的规则是:

对于每一对可行函数F1和F2,从第i个参数到第i个参数的隐式转换序列进行排序,以确定哪个更好。

如果 F1 的所有参数的隐式转换不比 F2 的所有参数的隐式转换差,并且 ... F1 的至少一个参数的隐式转换为比 F2 的那个参数对应的隐式转换更好。

所以给定重载集:

int func(int, int);        // #1
int func(double, double);  // #2 

让我们考虑以下调用:

func(1, 1);    // perfect match for #1, so #1 is chosen

func(1., 1.);  // perfect match for #2, so #2 is chosen

func(1., 1);   // could call #1 by converting 1st argument to int 
               // (floating-integral conversion)

               // could call #2 by converting 2nd argument to double 
               // (floating-integral conversion)

               // error: ambiguous (equal number of conversions needed for both #1 and #2)

func(1ll, 1.); // could call #1 by converting both arguments to ints
               // (integral conversion for 1st argument, floating-integral conversion for 2nd argument)

               // could call #2 by converting just 1st argument to double
               // (floating-integral conversion for 1st argument)

               // for the 2nd parameter, #2 is ranked as a better choice, 
               // since it has a better implicit conversion sequence for #2
               // and so #2 is chosen (even though both #1 and #2 are tied for the 1st argument)

现在让我们添加第三个重载:

int func(float, float);  // #3

现在当您拨打电话时:

func(1, 1.f);  // could call #1 by converting 2nd argument to int
               // (floating-integral conversion for 2nd argument)

               // could call #2 by converting 1st argument to double, and converting 2nd argument to double 
               // (floating-integral conversion for 1st argument, and floating-point promotion for 2nd argument)

               // could call #3 by converting 1st argument to float  
               // (floating-integral conversion for 1st argument)

               // error: ambiguous (equal number of conversions needed for #1, #2 and #3)

【讨论】:

这个答案不正确。 C++ 每个参数最多执行一次转换,但转换的总数无关紧要。 OP 代码中发生的情况是选择了扩大转换,因为 C++ 永远不会执行缩小参数转换。 @user207421 允许编译器对函数参数执行缩小转换,但如果可能,它会选择扩大转换。需要发布关于缩小转换的诊断。仅在列表初始化中不允许缩小转换。 @user207421: Narrowing conversions are allowed. @user2357112supportsMonica -- 编译器最多应用一次用户定义的转换;它还可以应用内置转换(我在想两个,但我在这里很模糊)。并且允许缩小转换。您必须阅读重载解决规则;它们很复杂,简单的答案总是错误的。 @user207421,转换总数本身并不重要,因为逻辑是每个参数,但是因为没有转换比一些转换更好,所以更少的转换永远不会更糟,尽管它仍然可能是模棱两可。

以上是关于为啥在传递 long long 时调用具有两个 double 类型参数的重载函数?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的 C 代码片段不起作用?简化版可以。为 unsigned long long 传递不带 VA_ARGS 的 args

为啥最小的 int -2147483648 的类型为“long”? [复制]

如何在 KML URL 上传递多个 Lat 和 Long?

为啥这两个指针减法会给出不同的结果?

c语言中long型的65530转化为int型是多少啊?为啥啊?

为啥这个用于 lat/long 的 Lua Haversine 代码不起作用?