首页 文章

为什么用整数字面调用重载的ambig(long)和ambig(unsigned long)是不明确的?

提问于
浏览
31

编译时

void ambig(  signed long) { }
void ambig(unsigned long) { }

int main(void) { ambig(-1); return 0; }

我明白了

error C2668: 'ambig' : ambiguous call to overloaded function
    could be 'void ambig(unsigned long)'
    or 'void ambig(long)'
while trying to match the argument list '(int)'

我知道我可以通过说 -1L 而不是 -1 ,但为什么/如何在一开始就被认为是模棱两可的?

3 回答

  • 8

    您正在将 int 传递给此重载函数 .

    虽然人类的直觉说_1336250应该是首选,因为你的输入是一个负整数(不能用 unsigned long 表示),这两个转换在C中实际上等同于"precedence" .

    也就是说,转换 intunsigned long 被认为与 intsigned long 一样有效,并且两者都不优先 .

    另一方面,如果您的参数已经是 long 而不是 int ,则与 signed long 完全匹配,无需转换 . This avoids the ambiguity .

    void ambig(  signed long) { }
    void ambig(unsigned long) { }
    
    int main(void) { ambig(static_cast<long>(-1)); return 0; }
    

    “只是其中之一” .


    [C 11:4.13 / 1] :(“整数转换等级”)每个整数类型都有一个整数转换等级,定义如下:[..]有符号整数类型的等级应大于任何有符号整数的等级类型较小的 . long long int的等级应大于long int的等级,该等级应大于int的等级,其应大于short int的等级,short rank应大于signed char的等级 . 任何无符号整数类型的等级应等于相应的有符号整数类型的等级 . [..] [注意:整数转换排名用于整数促销(4.5)的定义和通常的算术转换(第5条) . - 尾注]

    重载分辨率很复杂,在 [C++11: 13.3] 中定义;我不会在这里引用大部分内容而烦恼你 .

    不过,这里有一个亮点:

    [C 11:13.3.3.1/8]:如果不需要转换来将参数与参数类型匹配,则隐式转换序列是由标识转换(13.3.3.1.1)组成的标准转换序列 . [C 11:13.3.3.1/9]:如果找不到将参数转换为参数类型的转换序列,或者转换结果不正确,则无法形成隐式转换序列 . [C 11:13.3.3.1/10]:如果存在几个不同的转换序列,每个转换序列都将参数转换为参数类型,则与参数关联的隐式转换序列被定义为指定为模糊转换序列的唯一转换序列 . 为了对如13.3.3.2中描述的隐式转换序列进行排序,将模糊转换序列视为用户定义的序列,其与任何其他用户定义的转换序列134无法区分 . 如果选择使用模糊转换序列的函数作为最佳可行函数,则调用将是错误的,因为调用中的一个参数的转换是不明确的 .

    • /10 就是你遇到的情况; /8 是您使用 long 参数的情况 .
  • 3

    常量 -1 的类型为 int . 所以你用 int 作为参数调用 ambig . ambig 没有接受 int 的重载,因此我们必须查看我们可以执行的隐式转换 . int 可以隐式转换为 longunsigned long (以及其他内容),这两者都是 ambig 的有效参数 . 所以编译器不知道要选择哪个转换,你需要手动转换(或使用长常量( -1l )而不是int常量开始) .

    -1 是一个负数这一事实并没有看到参数值,只是它的类型 .

  • 33

    因为 -1 的类型为 int . 并且 int 可以隐式转换为 signed longunsigned long .

相关问题