"ambiguous overload for 'operator[]'" if conversion operator to int exist

c++

Solution

The problem is that your class has a conversion operator to `uint32_t`, so the compiler does not know whether to:

- Construct a `std::string` from the string literal and invoke your overload accepting an `std::string`;

- Convert your `Foo` object into an `uint32_t` and use it as an index into the string literal.

While option 2 may sound confusing, consider that the following expression is legal in C++:

1["foo"];

This is because of how the built-in subscript operator is defined. Per Paragraph 8.3.4/6 of the C++11 Standard:

Except where it has been declared for a class (13.5.5), the subscript operator [] is interpreted in such a way that `E1[E2]` is identical to `*((E1)+(E2))`. Because of the conversion rules that apply to +, if `E1` is an array and `E2` an integer, then `E1[E2]` refers to the `E2`-th member of `E1`. Therefore, despite its asymmetric appearance, subscripting is a commutative operation.

Therefore, the above expression `1["foo"]` is equivalent to `"foo"[1]`, which evaluates to `o`. To resolve the ambiguity, you can either make the conversion operator `explicit` (in C++11):

struct Foo
{
    explicit operator uint32_t() { /* ... */ }
//  ^^^^^^^^
};

Or you can leave that conversion operator as it is, and construct the `std::string` object explicitly:

    f[std::string("foo")];
//    ^^^^^^^^^^^^     ^

Alternatively, you can add a further overload of the subscript operator that accepts a `const char*`, which would be a better match than any of the above (since it requires no user-defined conversion):

struct Foo
{
    operator uint32_t() { /* ... */ }
    Foo& operator[](const std::string &foo) { /* ... */ }
    Foo& operator[](size_t index) { /* ... */ }
    Foo& operator[](const char* foo) { /* ... */ }
    //              ^^^^^^^^^^^
};

Also notice, that your functions have a non-void return type, but currently miss a `return` statement. This injects Undefined Behavior in your program.

Problem

I'm trying to implement the vector like and the map like `[]` operator for a class. But I get error messages from my compilers (g++ and clang++). Found out that they only occurs if the class has also conversion operators to integer types. Now I have two problems. The first is that I don't know why the compiler can't distinguish between `[](const std::string&)` and `[](size_t)` when the class has conversion operators to ints. The second... I need the conversion and the index operator. How to fix that? works: ``` #include <stdint.h> #include <string> struct Foo { Foo& operator[](const std::string &foo) {} Foo& operator[](size_t index) {} }; int main() { Foo f; f["foo"]; f[2]; } ``` does not work: ``` #include <stdint.h> #include <string> struct Foo { operator uint32_t() {} Foo& operator[](const std::string &foo) {} Foo& operator[](size_t index) {} }; int main() { Foo f; f["foo"]; f[2]; } ``` compiler error: ``` main.cpp: In function 'int main()': main.cpp:14:9: error: ambiguous overload for 'operator[]' in 'f["foo"]' main.cpp:14:9: note: candidates are: main.cpp:14:9: note: operator[](long int, const char*) <built-in> main.cpp:7:7: note: Foo& Foo::operator[](const string&) main.cpp:8:7: note: Foo& Foo::operator[](size_t) <near match> main.cpp:8:7: note: no known conversion for argument 1 from 'const char [4]' to 'size_t {aka long unsigned int}' ```

Original source