为啥在传递 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”? [复制]