Resolving ambiguous operator overload []

I have this class:

class MyClass { public: int operator[](const std::string&); const std::string& operator[](const int&) const; ... }; 

It works very hard, however, if I call the second operator w / const literal 0:

 MyClass myclass; std::cout << myclass[0] << std::endl; 

I got this error:

 In function 'int main()': ambiguous overload for 'operator[]' in 'myclass[0]' note: candidates are: note: const int MyClass::operator[](const string&)| note: const string& MyClass::operator[](const int&) const 

I understand that I understand that the situation (0 can be either a string or an int?), But my question is: is there a way to resolve this and save the operator overload?

+6
source share
3 answers

A call to MyClass::operator[](const std::string&) involves the conversion:

myclass from MyClass& to MyClass& : perfect match

0 from int to const char* to std::string : custom conversion

A call to MyClass::operator[](const int&) const enables the conversion:

myclass from MyClass& to const MyClass& : const qualification

0 from int to int : perfect match

In such a situation, when one overload is β€œbetter” for argument X, but the other overload is β€œbetter” for argument Y, neither overload can be considered the best overload, and the compiler should complain (except for the third overload it hits both).

Is it possible to change two overloads on both const and non-const ? If not, you can add a third overload to handle this situation:

 const std::string& operator[](int n) { return static_cast<const MyClass&>(*this)[n]; } 
+6
source

0 cannot be a string , but it can be a pointer, which means that it can be implicitly converted to string . Please note that this does not apply to other constant integrals, for example, 1 or 42 - only 0 .

4.10 Convert Pointers

1 / The null pointer constant is the integral constant expression (5.19) of the rvalue of integer type, which is zero. The null pointer constant can be converted to a pointer type; the result is a null pointer to a value of this type, and a pointer to an object or a pointer to a function type is different from any other value. Two null pointer values ​​of the same type must be compared equal. The conversion of a null pointer constant to a pointer to a cv-qualified type is one conversion and not a sequence of pointer conversion with subsequent qualification conversion (4.4).

So, in the case of myclass[0] , 0 can be either an int constant or a `null pointer.

The standard also states that std::string has a non- explicit constructor that accepts a char pointer:

 size_type find_last_not_of (const charT* s, size_type pos = npos) const; 

Now, since your operator& methods take parameters of a const reference type, they can be passed temporary. This is why the compiler is confused - it does not know which one you want - one that accepts int , or one that takes up a temporary string constructed with string(const char*) .

As for the solution to this problem, I would take a step back. It seems to me that your two operator[] functions do completely different things. Or maybe they do the same thing, given the different inputs. If they do different things, I would provide member functions that have different (corresponding) names, and skip trying to use the operator[] syntax. Perhaps one of these methods returns what is actually indexed - in this case, I would use the operator[] syntax for this, but only that.

If they really do the same thing, and that the point is to return the element by index, I would provide only one method for this and would require size_t by value. Then you can also provide some conversion function (preferably as a free, non-member function) that converts, say, string to size_t . Having done this, you can write your code, for example, when indexing a string :

 myPos[str_to_index(str)]; 
+4
source

Literal 0 is special. Besides being an octal constant, it can also be converted to a null pointer of any type of pointer. This makes 0 viable for the std::string char const * constructor.

The reason that no overload is better is because the int overload of the statement has a CV const qualifier. Thus, both overloads require conversion and are equally bad.

The obvious workaround should be explicit regarding the need to overload const:

 static_cast<MyClass const &>(myclass)[0] 
+3
source

All Articles