0
votes

I have a question about an unexpected conversion:

class BadString
{
 public:
    BadString(char const*);
    ...
    char& operator[] (size_t);            //(1)
    char const& operator[] (size_t);

    operator char* ();                    //(2)
    operator char const* ();

};

int main()
{
    BadString str("correkt");
    str[5] = 'c';  //possibly an overload resolution ambiguity !!!
}

The explanation goes like this:

The subscript operator at (1) seems like a perfect match. However is not quite perfect because the argument 5 has type int, and the operator expects size_t (unsigned int or unsigned long, but never int). Still, a simple standard integer conversion makes (1) easily viable. However, there is another candidate: the built-in subscript operator. Indeed, if we apply the conversion operator (2) to str, we obtain a pointer type, and now the the built-in subscript operator applies. This operator takes a ptrdiff_t argument, which on many platforms is equivalent to int.

I understand that the original parameters for (1) was not matched, and then an implicit conversion will take place, but I don't understand why the compiler will try to convert str, using (2).

Thank you.

1
Your code shouldn't compile: you are overloading operator[] by return type. - juanchopanza
You need to make the function char const& operator[] (size_t) constant, e.g. char const& operator[] (size_t) const; - Some programmer dude
It's good form to indicate the source when you're quoting things. - molbdnilo
Have implicit operator char * is a bad idea anyway - Slava
"C++ Templates, the complete guide", VanDeVoorde & Josuttis: B.2.1 The Implied Argument for Member Functions - user2286810

1 Answers

2
votes

If I 'expand' your code like this and make second subscript operator method const, so the result will be

#include <iostream>
#include <cstring>

class BadString {
  public:
      char s[1024];
      BadString(const char* s_)  {
          strncpy(s, s_, strlen(s_) + 1);
      }
      char& operator[](size_t pos) {
          return s[pos];
      }
      const char& operator[](size_t pos) const {
          return s[pos];
      }

      operator char*() {
          std::cout << "operator char*\n";
      }

      operator const char*() {
          std::cout << "operator const char*\n";
      }
};

int main() {
    BadString bs("correkt");
    bs[5] = 'c';
    std::cout << bs.s << "\n";
}

then compile it and run, it works as expected, output is just one line

correct

Such fact as (2) implicit conversion operator takes place means you did not provide full information about BadString class. Maybe you should do so.

And, of course, if it is implemented like in provided example, there is no any reason to call (2) implicit conversion operator.

UPD: Thinking about what you mentioned in comment, I suppose the purpose of operator const char*() was that explicit conversion like

(const char*)bs

returned pointer to first element of an array s, that bs is holding. That is, of course, incorrect, and a bit ugly, but there is the only option that I see.