I have the following test code:
#include <string>
#include <iostream>
class CString
{
public:
CString(char const*) {}
};
class TestBed
{
public:
void Comparison(CString const&) { std::cout << "CString Overload" << std::endl; }
void Comparison(std::string const&) { std::cout << "std::string overload" << std::endl; }
};
int main()
{
TestBed tb;
tb.Comparison("Hello World");
}
This code fails to compile because the call to Comparison()
is ambiguous. I expect this behavior.
However, when I make either of the Comparison()
overloads const
, as in: void Comparison(std::string const&) const
or void Comparison(CString const&) const
(but not both), the code compiles and chooses the non-const overload.
Overload resolution rules are pretty complex and I haven't seen anything that describes how const
affects this situation. My understanding is:
- Function with exact matching argument is chosen first
- 1-level implicit conversion is tried next
In both cases, 1 & 2 are ambiguous. Can someone explain this? Thanks.
Best Answer
For class methods, the
this
part is considered as if it were an extra argument. So if you made theCString
one const, that makes the overload set:For
(1)
, we need to do two conversions: aconst
conversion, and a conversion toCString
. But for(2)
, we only need to do a single conversion: tostd::string
. Thus,(2)
is preferred.We can verify this by adding a third function that does one single conversion for
this
:Here, we again only have a single conversion (in the "first" argument), and thus the overload set is ambiguous.
In [over.match.funcs]:
That establishes why we consider
const TestBed&
vsTestBed&
. And then it's just a matter of comparison the conversion sequences between the overloads(1)
and(2)
. For the 2nd argument, both conversion sequences are equal, but for the 1st argument,(2)
has a better conversion sequence (namely Exact) - which is why it wins without ambiguity.