literal `0` being a valid candidate for int and const string& overloads causes ambiguous call
0
is special in C++. A null pointer has the value of 0
so C++ will allow the conversion of 0
to a pointer type. That means when you call
a.f(0);
You could be calling void f(int i = 0) const
with an int
with the value of 0
, or you could call void f(const std::string&)
with a char*
initialized to null.
Normally the int
version would be better since it is an exact match but in this case the int
version is const
, so it requires "converting" a
to a const CppSyntaxA
, where the std::string
version does not require such a conversion but does require a conversion to char*
and then to std::string
. This is considered enough of a change in both cases to be considered an equal conversion and thus ambiguous. Making both functions const
or non const
will fix the issue and the int
overload will be chosen since it is better.
My question is why compiler only complained about it when the parameter was 0.
Because 0 is not only an integer literal, but it is also a null pointer literal. 1 is not a null pointer literal, so there is no ambiguity.
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.
If both overloads are const
qualified, then the implicit object argument conversion sequence is identical, and thus one of the overloads is unambiguously preferred.