Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use of overloaded operator[] is ambiguous

Tags:

c++

Simplified code as below:

#include <string>
#include <string_view>

struct object{
  operator std::string(){return "";}
}

struct foo{
  foo operator[](std::string_view s){
    return foo{};
  }
  
  template <typename T>
  operator T(){
    return object{};
  }
};

int main(){
  foo f;
  std::string s = f["a"];
}

clang gives an error:

error: use of overloaded oeprator '[]' is ambiguous (with oeprand types 'foo' and 'const char*')
note: candidate function foo operator[](std::string_view s)
note: built-in candidate operator[](long, const char*)
note: built-in candidate operator[](long, const volatile char*)

but gcc compiles above code successfully.

clang version is 12.0.1, gcc is 7.5.0

I'm confused, which compiler is right?

like image 242
user9132451 Avatar asked Sep 16 '25 11:09

user9132451


1 Answers

template <typename T>
operator T(){
    return object{};
}

I think clang is correct here, since this snippet makes the foo class convertible to any type, and viable template functions are supposed to be instantiated before overload resolution comes into play:

Before overload resolution begins, the functions selected by name lookup and template argument deduction are combined to form the set of candidate functions

As you can see, the overload struggles with the following arguments: (long, const char*), so it has to be expression similar to this 3["a"] which is perfectly legal as per cppreference:

expr1 [ expr2 ]

For the built-in operator, one of the expressions (either expr1 or expr2) must be a glvalue of type “array of T” or a prvalue of type “pointer to T”, while the other expression (expr2 or expr1, respectively) must be a prvalue of unscoped enumeration or integral type. The result of this expression has the type T


However it also gives a clue how to differentiate between built-in subscript and custom overloads:

expr1 [ { expr, ... } ]

The form with brace-enclosed list inside the square brackets is only used to call an overloaded operator[].

So you should be good if the said example is written like this:

int main(){
    foo f;
    std::string s = f[{"a"}];
    return 0;
}

Or convert the subscript to string explicitly, so the compiler doesn't confuse it with built-in operator for arrays:

int main(){
    using namespace std::string_literals;
    
    foo f;
    std::string s = f["a"s];
    return 0;
}
like image 177
The Dreams Wind Avatar answered Sep 19 '25 01:09

The Dreams Wind