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

Tor*_*day 50 c++ double overloading overload-resolution

我写了这两个重载:

int func(int, int) {
    return 1;
}

int func(double, double) {
    return 2;
}
Run Code Online (Sandbox Code Playgroud)

当我使用明显的两个调用方案(即func(1, 1)and )调用它们时,分别调用func(1.0, 1.0)了第一个和第二个重载函数,并且当我尝试调用func(1, 1.0)它时会出现错误,但是当我将1a强制转换为 a 时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.
}
Run Code Online (Sandbox Code Playgroud)

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

cig*_*ien 50

选择调用重载集中的哪个函数(即重载解析)取决于(部分)函数调用的多少参数必须经过隐式转换,以及需要什么样的转换。

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

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

如果 F1 的所有参数的隐式转换不比 F2 的所有参数的隐式转换差,则确定 F1 是比 F2 更好的函数,并且 ... F1 的至少一个参数的隐式转换优于F2 的那个参数的相应隐式转换。

所以给定重载集:

int func(int, int);        // #1
int func(double, double);  // #2 
Run Code Online (Sandbox Code Playgroud)

让我们考虑以下调用:

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)
Run Code Online (Sandbox Code Playgroud)

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

int func(float, float);  // #3
Run Code Online (Sandbox Code Playgroud)

现在,当您拨打电话时:

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)
Run Code Online (Sandbox Code Playgroud)

  • 这个答案不正确。C++ 对每个参数最多执行一次转换,但转换总数无关紧要。OP 代码中发生的情况是选择了扩大转换,因为 C++ 永远不会执行缩小参数转换。 (2认同)
  • @user207421允许编译器对函数参数执行缩小转换,但如果可能的话它会选择扩大转换。需要对缩小转换进行诊断。仅在列表初始化中不允许缩小转换。 (2认同)
  • @user207421:[允许缩小转换范围。](https://ideone.com/ZUnnp5) (2认同)