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

  • A+

The following code compiles well in gcc 7.3.0, but doesn't compiles with clang 6.0.0.

#include <string>  struct X {     X() : x(10) {}     int operator[](std::string str) { return x + str[0]; }     template <typename T> operator T() { return x; } // (1) fails only in clang     //operator int() { return x; } // (2) fails both in gcc and clang private:     int x; };  int main() {     X x;     int y = 20;     int z = int(x);     return x["abc"]; } 

I used command clang++ 1.cpp -std=c++98 with specifying different standard versions. I tried c++98,11,14,17,2a. In all cases an error is the same. Error message in clang is following:

1.cpp:14:13: error: use of overloaded operator '[]' is ambiguous (with operand types 'X' and 'const char [4]')     return x["abc"];            ~^~~~~~ 1.cpp:5:9: note: candidate function     int operator[](std::string str) { return x + str[0]; }         ^ 1.cpp:14:13: note: built-in candidate operator[](long, const char *)     return x["abc"];             ^ 1.cpp:14:13: note: built-in candidate operator[](long, const volatile char *) 1 error generated. 

What compiler correctly follows the standard in this situation? Is it a valid code?

The description of the problem can be found here, but it is about situation (2). I am interested in case (1).


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

[]/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. [] 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.


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: