Ambiguity Issues
Suppose you're designing a simple string class. Naturally, your class defines a conversion functions to char * and an overloaded [] operator. Each of these functions has a const and a non-constversion:
class BuggyString {
char buf[100];
public:
BuggyString(const char* s);
//subscripting
char& operator[] (size_t n);
const char& operator[] (size_t n) const;
//implicit conversion to char*
operator char* ();
operator const char* () const;
};
When some compilers compile the following code, they issue a compilation error:
BuggyString str("buggi");
str[4] = 'y'; //error, overload resolution ambiguity
Where does this error come from? When the compiler sees the expression str[4], it looks up the definition of str and discovers that str isn't an array. At this stage, there are two possible ways to interpret the expression str[4]:
- Invoking the overloaded [] member function.
- Invoking BuggyString::operator char *, and then applying the built-in [] operator to the result.
In other words, depending on the underlying type of std::ptrdiff_t (which affects overload resolution) the compiler is faced with two options: either interpret str[4]as:
str.operator[](4) //call overloaded []
or interpret it as:
str.operator char*()[4]//call operator char* +built-in []
In C++03, the common approach is to avoid conversion functions in the first place. The std::string class, for example, defines the member function string::c_str() as a substitute for operator const char *. This approach works well when the destination type is known at compile time. However, when templates are involved, named functions are problematic because the destination type can only be determined when you instantiate a template.