error: ambiguous overload for 'operator[]'
Asked Answered
W

1

5

I have an error I don't understand. The following snippet compiles

#include <iostream>

class Foo
{
    std::string m_name;

public:

    explicit Foo(std::string const& name):m_name{name}{}

    Foo operator[](int index) const {std::cout<<"size_t const\n"; return Foo{m_name};}
    Foo operator[](std::string const& name) const { std::cout<<"str const\n"; return Foo{name}; }
};

int main()
{
    Foo foo{"Cool"};
        
    foo[0]; 
    foo[1]; 
    
    return 0;
}

but the following doesn't not compile for index=0 when I overload the operator[](std::string const&)

#include <iostream>

class Foo
{
    std::string m_name;

public:

    explicit Foo(std::string const& name):m_name{name}{}

    Foo operator[](int index) const {std::cout<<"size_t const\n"; return Foo{m_name};}
    Foo operator[](std::string const& name) const { std::cout<<"str const\n"; return Foo{name}; }
    Foo operator[](std::string const& name) { std::cout<<"str non const\n";  return Foo{name}; } //doesn't compile with
};

int main()
{
    Foo foo{"Cool"};
        
    foo[0]; //doesn't compile
    foo[1]; //compile
    
    
    return 0;
}

and in this case I have the following compile-error:

main.cpp: In function 'int main()':
main.cpp:25:8: error: ambiguous overload for 'operator[]' (operand types are 'Foo' and 'int')
  25 |     foo[0]; //doesn't compile
main.cpp:12:5: note: candidate: 'Foo Foo::operator[](int) const'
  12 | Foo operator[](int index) const {std::cout<<"size_t const\n"; return Foo{m_name};}
main.cpp:13:5: note: candidate: 'Foo Foo::operator[](const std::string&) const'
  13 | Foo operator[](std::string const& name) const { std::cout<<"str const\n"; return Foo{name}; }
main.cpp:14:5: note: candidate: 'Foo Foo::operator[](const std::string&)'
  14 | Foo operator[](std::string const& name) { std::cout<<"str non const\n";  return Foo{name}; } //doesn't compile with     
  1. Why adding an overload with a std::string parameter make the foo[0] ambiguous ?
  2. And why the problem is only with the index 0 ?
Washburn answered 3/3, 2023 at 10:22 Comment(3)
There is a defect in standard library - ::std::string constructors are implicit and a a general language defect allowing 0 literal to be treated as a null pointer constant. So 0 can be implicitly converted into string . @MarekR add -Wpedantic to enforce standard conformanceSkimmer
Problem is caused by fact that 0 is a special value, which can be converted to any pointer. So it can be treated as const char* which is implicitly convertible to std::string. Using +0 will trick compiler to assume type is int (MSVC tdo not respect that): godbolt.org/z/PW3Eoj57eHomocyclic
But why overloading operator[](std::string const&) with a non-const member triggers the compile error ?Washburn
A
6

The problem is that the constructor std::string::string(const char*) is not explicit(and 0 is a null pointer constant) which means that the both the overloads Foo::Foo operator[](int) const and Foo::Foo operator[](const std::string&) are viable but have the same rank. This in turn means that the call is ambiguous since neither of them is better than the other.

In particular, Foo::Foo operator[](int) const requires conversion for its first implicit parameter but no conversion for its second int parameter. On the other hand, Foo::Foo operator[](const std::string&) requires no conversion for its first implicit parameter but requires an implicit conversion from 0 to std::string using the constructor std::string::string(const char*). And as neither of these overloads is better than the other, the call is ambiguous.


Note that this problem doesn't occur between the overloads Foo::Foo operator[](int) const and Foo::Foo operator[](const std::string&) const because in this case the former is a better match than the latter as it doesn't require any conversion for its second int argument and both of these overloads requires a conversion for their first implicit parameter.


Thus one simple(straightforward) fix is to add a non-const overload Foo::Foo operator[](int index).

Asta answered 3/3, 2023 at 10:47 Comment(1)
@leosch Yes, that was a typo. Fixed now.Asta

© 2022 - 2024 — McMap. All rights reserved.