Reputation: 59
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?
Upvotes: 4
Views: 395
Reputation: 8968
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
orexpr2
) must be a glvalue of type “array ofT
” or a prvalue of type “pointer to T”, while the other expression (expr2
orexpr1
, respectively) must be a prvalue of unscoped enumeration or integral type. The result of this expression has the typeT
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;
}
Upvotes: 2