文字“ 0”是int和const字符串的有效候选者,并且重载导致模棱两可的调用

Con*_* Ma 44 c++ overloading ambiguous-call

我最近修复了一个错误。

在以下代码中,一个重载函数是const,而另一个则不是。通过将两个函数都设为const可以解决此问题。

我的问题是为什么编译器只在参数为0时才抱怨它。

#include <iostream>
#include <string>

class CppSyntaxA
{
public:
    void f(int i = 0) const { i++; }
    void f(const std::string&){}
};

int main()
{
    CppSyntaxA a;
    a.f(1);  // OK
    //a.f(0);  //error C2666: 'CppSyntaxA::f': 2 overloads have similar conversions
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Nat*_*ica 56

0在C ++中是特殊的。空指针的值为,0因此C ++允许将转换为0指针类型。那意味着当你打电话

a.f(0);
Run Code Online (Sandbox Code Playgroud)

你可以调用void f(int i = 0) constint同值0,或者你可以调用void f(const std::string&)一个char*初始化为空。

通常情况下,int版本会更好,因为它是完全匹配的,但在这种情况下,int版本是const,因此它需要“转换” aconst CppSyntaxA,其中std::string版本不需要进行此类转换,但需要先转换为char*,然后转换为std::string。在两种情况下,这都足以视为相等的转换,因此模棱两可。同时启用const或禁用这两个功能const将解决此问题,并int选择过载,因为这样做更好。

  • @JesperJuhl空指针和`nullptr`是不同的东西。[null指针是一个值为'0'的整数](https://timsong-cpp.github.io/cppwp/conv.ptr#1.sentence-1),并且也是一个null值prull 。 (4认同)
  • 空指针的值为“ 0”?那是新的。它是由实现定义的,具有什么值,尽管字面量“ 0”可以隐式转换为任何空指针类型,因此它将比较相等。尽管((大多数?)现代平台上都支持(intptr_t)(void *)0 == 0`,但不能保证。@JesperJuhl似乎您使用`nullptr`偏离了轨道。 (4认同)
  • @FrançoisAndrieux不用担心,编译器实现者也是如此;) (2认同)
  • 这个重载问题中最令人恼火的部分是使用空指针:/来调用`std :: string`的构造函数是UB。 (2认同)

eer*_*ika 11

我的问题是为什么编译器只在参数为0时才抱怨它。

因为0不仅是整数文字,而且还是空指针文字。1不是空指针文字,因此没有歧义。

The ambiguity arises from the implicit converting constructor of std::string that accepts a pointer to a character as an argument.

Now, the identity conversion from int to int would otherwise be preferred to the conversion from pointer to string, but there is another argument that involves a conversion: The implicit object argument. In one case, the conversion is from CppSyntaxA& to CppSyntaxA& while in other case it is CppSyntaxA& to const CppSyntaxA&.

So, one overload is preferred because of one argument, and the other overload is preferred because of another argument and thus there is no unambiguously preferred overload.

The issue will be fixed by making both functions const.

如果两个重载都const合格,则隐式对象参数转换序列相同,因此,无疑要选择其中一个重载。