Use of overloaded operator '[]' is ambiguous with template cast operator

The issue is that there is one conversion on each path:

  • first from "abc" to std::string and then operator[] call.
  • second from x to std::ptrdiff_t and then the operator[] for an std::ptrdiff_t and a const char*.

So the solution is to make the conversion operator explicit:

int operator[](const std::string& str) { return x + str[0]; }
template <typename T>
explicit operator T() { return x; } // (1) fails only in clang

GCC is wrong. The template case shouldn't make any difference.

[over.match.best]/1 says:

Define ICSi(F) as follows:

  • ...

  • let ICSi(F) denote the implicit conversion sequence that converts the i-th argument in the list to the type of the i-th parameter of viable function F. [over.best.ics] defines the implicit conversion sequences and [over.ics.rank] defines what it means for one implicit conversion sequence to be a better conversion sequence or worse conversion sequence than another.

Given these definitions, a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and ...

The two viable candidates are

int         operator[](X&,             std::string); // F1
const char& operator[](std::ptrdiff_t, const char*); // F2

... and ICS1(F1) (X -> X&) is better than ICS1(F2) (X -> std::ptrdiff_t), no matter whether or not X -> std::ptrdiff_t is through a template conversion function, but ICS2(F1) (const char[4] -> std::string) is worse than ICS2(F2) (const char[4] -> const char*). So neither function is better than the other, resulting in ambiguity.

This has been reported as a GCC bug.