文字“0”是 int 和 const string& 重载的有效候选者会导致调用不明确

literal `0` being a valid candidate for int and const string& overloads causes 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;
}

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

a.f(0);

您可以使用值为 0int 调用 void f(int i = 0) const,或者您可以使用初始化为 null 的 char* 调用 void f(const std::string&) .

通常 int 版本会更好,因为它是完全匹配但在这种情况下 int 版本是 const,因此需要 "converting" aconst CppSyntaxA,其中 std::string 版本不需要这样的转换,但需要先转换为 char*,然后再转换为 std::string。在这两种情况下,这被认为是足够的变化,可以被认为是相等的转换,因此是不明确的。使两个函数 const 或非 const 将解决问题,并且将选择 int 重载,因为它更好。

My question is why compiler only complained about it when the parameter was 0.

因为0不仅是整型字面量,而且还是空指针字面量。 1 不是空指针字面量,所以没有歧义。

歧义来自 std::string 的隐式转换构造函数,该构造函数接受指向字符的指针作为参数。

现在,从 int 到 int 的身份转换比从指针到字符串的转换更受欢迎,但是还有另一个涉及转换的参数:隐式对象参数。在一种情况下,转换是从 CppSyntaxA&CppSyntaxA&,而在另一种情况下,它是从 CppSyntaxA&const CppSyntaxA&

因此,一个重载因一个参数而首选,另一个重载因另一个参数而首选,因此没有明确首选的重载。

The issue will be fixed by making both functions const.

如果两个重载都是 const 合格的,则隐式对象参数转换序列是相同的,因此其中一个重载是明确首选的。