How does the const modifier for member functions affect overload resolution?

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 does not compile because the call to Comparison() ambiguous. I expect this behavior.

However, when I do one of the Comparison() const overloads, as in: void Comparison(std::string const&) const or void Comparison(CString const&) const (but not both), the code compiles and selects the non-constant overload.

The rules for overload resolution are quite complex, and I have not seen anything that describes how const affects this situation. I understand:

  • First, a function with an exact matching argument is selected
  • 1-level implicit conversion is checked further

In both cases, 1 and 2 are ambiguous. Can someone explain this? Thanks.

+8
c ++ overloading c ++ 11
source share
1 answer

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.

+7
source share

All Articles