I was certain it was asked before, but I couldn't find it.
I have a class encapsulating std::string
. Inside I want to overloaded both typecasts to char*
and the access operator[]
.
class String
{
public :
String(const char* s) { m_str = s; }
const char* str() const { return m_str.c_str(); }
char* str() { return &m_str[0]; }
char operator[](size_t pos) const { return m_str[pos]; }
char& operator[](size_t pos) { return m_str[pos]; }
operator const char*() const { return str(); } // cast operator
operator char*() { return str(); } // cast operator
protected:
std::string m_str;
};
void main()
{
String s = "1234";
if(s[0] != '1') //'String::operator []': 4 overloads have similar conversions !!!!!
std::cout << "Error" << endl;
}
Problem is now of course when I try to use String []
I receive error:
4 overloads have similar conversions
The compiler can't decide what to do:
operator[]
directlychar*
, use operator()
, and finally operator[]
over the resulting char*
arrayIs there some way to keep both operators? For many functions, it is very helpful to have char*
and const char*
to use operator() of String
but in all other cases directly the operator[] (not trying to convert to char*
first).
I suppose the answer to this is probably No. That is why in std::string
there is no char*
cast operator, but maybe something has changed in more recent C++ standards?
EDIT: I can compile the above with GCC but it fails with VS (x86).
Error C2666 'String::operator []': 4 overloads have similar conversions
Always compile your code with warnings enabled, for gcc
and clang
the command line option is -Wall -Wextra -Werror
. The warnings will tell you that operator[]
needs to return a value.
In expression s[0]
in 32-bit mode clang
and msvc
compilers consider the standard conversion of int
index to unsigned
(32-bit size_t
) to be of the same rank as user-defined conversion of String
to char*
. See the compiler error messages here. The latter conversions being a user-defined conversion has worse rank than any standard conversion, but the compilers cannot resolve this tie. I am not sure which exactly standard rule applies here.
A fix is to add another overload of operator[]
that accepts a signed ptrdiff_t
index:
char operator[](ptrdiff_t pos) const { return m_str[pos]; }
char& operator[](ptrdiff_t pos) { return m_str[pos]; }