过载模糊(int - > int64_t vs int - > double)

时间:2016-08-04 16:20:39

标签: c++

为什么intint64_tint的隐式转换为double不明确?

我原以为整数重载优先于浮点积分?

#include <stdint.h>

void foo(double) {}
void foo(int64_t) {}

int main()
{
    foo(5);
    return 0;
}
main.cpp: In function ‘int main()’:
main.cpp:8:10: error: call of overloaded ‘foo(int)’ is ambiguous
     foo(5);
          ^
main.cpp:3:6: note: candidate: void foo(double)
 void foo(double) {}
      ^
main.cpp:4:6: note: candidate: void foo(int64_t)
 void foo(int64_t) {}
      ^

我的环境是:

  • x86_64的
  • g ++ - 5.4(-std=c++14

int64_t在我的计算机上是long int

  

/usr/include/stdint.h

 # if __WORDSIZE == 64
 typedef long int        int64_t;
 # else

我已在我的测试应用程序中使用静态断言确认了这一点:

static_assert(__WORDSIZE == 64, "");
static_assert(std::is_same<int64_t, long int>::value, "");

我的构建标志是:

-std=c++14 -Werror -Wall -Wextra -m64 -msse2 -msse4.2 -mfpmath=sse 
-ftemplate-depth-128 -Wno-unused-parameter -pthread  -g -ggdb3 -O0 -fno-inline

4 个答案:

答案 0 :(得分:10)

来自[over.ics.user]表12我们有

enter image description here

正如您所见,整数和浮点促销具有相同的排名和整数,浮点转换具有相同的排名。

现在我们需要确定5 -> int64_t是否为整数提升或转化。如果我们检查[conv.prom] / 1,我们会找到

  

除了bool,char16_t,char32_t或wchar_t之外的整数类型的prvalue,其整数转换等级(4.13)小于int的等级,如果int可以表示所有的值,则可以转换为int类型的prvalue。来源类型;否则,源prvalue可以转换为unsigned int类型的prvalue。

促销在int停止,因此我们必须查看[conv.integral] / 1这是整数转换,我们有

  

整数类型的prvalue可以转换为另一个整数类型的prvalue。可以将未范围的枚举类型的prvalue转换为整数类型的prvalue。

这是怎么回事。所以5 -> int64_t是整数转换,5 -> double是浮点转换,两者的排名相同,因此重载分辨率不明确。

答案 1 :(得分:5)

我担心这真的归结为&#34; ,因为它是&#34;。

整数促销以int结束;没有促销大于int的类型。所以,你留下了两个标准的隐含转换,并且碰巧它们同样是很好的匹配。

  

[C++14: 4.5/1]:整数转换级别(4.13)小于boolchar16_tchar32_twchar_t的整数类型的prvalue如果int可以表示源类型的所有值,则int的等级可以转换为int类型的prvalue;否则,源prvalue可以转换为unsigned int类型的prvalue。

     

[C++14: 4.5/7]:这些转化称为整体促销

     

[C++14: 5/10]: [..] 此模式称为通常的算术转换,其定义如下:

     
      
  • 如果任一操作数是作用域枚举类型(7.2),则不执行任何转换;如果另一个操作数的类型不同,则表达式格式不正确。
  •   
  • 如果任一操作数的类型为long double,则另一个操作数应转换为long double
  •   
  • 否则,如果任一操作数为double,则另一个操作数将转换为double
  •   
  • 否则,如果任一操作数为float,则另一个操作数将转换为浮动。
  •   
  • 否则,应在两个操作数上执行整体促销(4.5) [..]
  •   

也许,当long intlong long int的使用变得流行时(特别是通过cstdint和朋友中的类型别名),可以修改标准以对这些类型引入整体促销。然后你的转换不会模棱两可。但是,许多现有代码也可能被破坏。

由于执行演员阵容是一个廉价的解决方案,我怀疑这被认为是值得的&#34;修复&#34;标准委员会。

也许有说服力的是,相对较新的固定宽度char类型可以以这种方式推广:

  

[C++14: 4.5/2]:类型char16_tchar32_twchar_t(3.9.1)的prvalue可以转换为以下第一种类型的prvalue表示其基础类型的所有值:intunsigned intlong intunsigned long intlong long intunsigned long long int。如果该列表中的任何类型都不能表示其基础类型的所有值,则可以将类型为char16_tchar32_twchar_t的prvalue转换为其基础类型的prvalue

答案 2 :(得分:0)

编译器是正确的...默认情况下,您的数字文字5的类型为int ...

要进行该函数调用,必须进行重载解析,这基本上会检查转换的可行性。请注意,这将是转换而不是促销的案例

现在,解释原因?我将引用cppreference的故事:(我知道,不是标准的替代品)

overload resolution选择最佳可行功能:

  

如果隐含的话,F1被确定为比F2更好的功能   F1的所有参数的转换都不比隐含的更糟糕   F2和

的所有参数的转换      
      
  1. 至少有一个F1的参数,其隐式转换优于该参数的相应隐式转换   F2
  2.   
  3. 或,......
  4.   
  5. 或,......
  6.   

现在让我们看看隐含conversion sequence是什么:

  

隐式转换序列按以下顺序组成:

     
      
  1. 零个或一个标准转换序列;
  2.   
  3. 。 。 。
  4.   

现在,让我们看看standard conversion sequence是什么:

  

标准转换序列由以下内容组成   顺序:

     
      
  1. 零或一个左值变换;
  2.   
  3. 零或一次数字促销或数字转换;
  4.   
  5. 。 。 。
  6.   

你有它,从这里开始参考NathanOliver's answer ..

中的表格

答案 3 :(得分:0)

编译器具有int-> doubleint-> int64_t的内置隐式转换。它不知道它需要使用哪个。

如果问题是在构造函数或类型转换运算符中发生的,则可以使用explicit关键字来禁用歧义。然后,您将需要为要调用的类型编写不同的重载方法(它们大多在进行显式转换+包装)。

对于函数/方法,它要简单得多:如果您有不需要隐式转换的重载方法,则编译器会选择该方法。只需开发

void foo(int64_t) {}

问题解决了。