For class methods, the this part is considered as an optional argument. Therefore, if you created a CString one const, this does the overload set:
Comparison(const TestBed&, CString const&) // (1) Comparison(TestBed&, std::string const&) // (2)
For (1) we need to do two conversions: a const conversion and a conversion to CString . But for (2) we need to do only one conversion: to std::string . Thus, (2) is preferred.
We can verify this by adding a third function that does one single conversion for this :
Comparison(const TestBed&, const char*) // (3)
Here we again have only one transformation (in the "first" argument), and therefore the set of overload is ambiguous.
In [over.match.funcs]:
it is considered that the member function has an additional parameter called the implicit parameter of the object, which represents the object for which the member function was called. For the purpose of overload resolution, both static and non-static member functions have an implicit object parameter, but designers do not.
For non-static member functions, the type of the implicit parameter of an object
- "lvalue reference to cv X" for functions declared without a ref-determinant or with a reflector-determinant
- "rvalue reference to cv X" for functions declared using && & ref-classifier
where X is the class of which the member is a member, and cv is the cv qualification on the member of the function declaration. [Example: for a const member function of class X, an additional parameter is supposed to be of type "reference to const X". -end example]
During overload resolution, the implied argument of an object is indistinguishable from other arguments.
This establishes why we consider const TestBed& vs TestBed& . And then it's just a matter of comparing the conversion sequences between overloads (1) and (2) . For the second argument, both conversion sequences are equal, but for the first argument (2) has the best conversion sequence (namely, Exact), so it wins without ambiguity.