warning for overload operator[]

I've got a compilation warning. It runs well but just a warning. Could someone please tell me why and what it is?...Thank.

CODE:

class A {
public:
A & operator[](const std::string & a) {
std::cout << "string" << std::endl;
return (*this);
}

const A & operator[](int a) const {
std::cout << "int" << std::endl;
return (*this);
}
};

int main() {
A a;
a["g"][3]; // OK here without using index 0
a[0]; // WARNING here if index is 0
return (0);
}


WARNING:

tmp.cc: In function ‘int main()’:
tmp.cc:21:8: warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second: [enabled by default]
a[0];
^
tmp.cc:12:15: note: candidate 1: const A& A::operator[](int) const
const A & operator[](int a) const {
^
tmp.cc:7:9: note: candidate 2: A& A::operator[](const string&)
A & operator[](const std::string & a) {
> It runs well but just a warning.

It is an error in a conforming implementation.

The cause for the error:

1. For overload resolution of calls to member functions, the arguments to the function are treated as if there is an extra argument (the implied argument forming the this pointer)
(Note that in this case, one of the member functions is const-qualified)

2. The literal 0 could be either the int zero or the nullptr


The error is reproduced in this snippet
(with simpler code, with explicit pointer arguments instead of an implicit this pointer)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <string>

struct A ;
void foo( A*, std::string ) ;
void foo( const A*, int ) ;

int main()
{
    A* pa = nullptr ;

    // Error: ambiguous call to overloaded function

    // void foo( A*, std::string ) : foo( pa, 0 )
    //    arg 1: exact match (A*), arg 2: conversion (nullptr to string)

    // void foo( const A*, int ) : foo( pa, 0 )
    //    arg1: conversion (pointer conversion A* to const A*). arg 2: exact match (int)
    foo( pa, 0 ) ;
}

http://coliru.stacked-crooked.com/a/069f68378cdb9bf8
https://rextester.com/KUN15223

The Microsoft compiler gives a helpful hint:
'note: qualification adjustment (const/volatile) may be causing the ambiguity'
@JLBorges, Thanks for your clarifying. But I am still confused of the solution, is it possible to implement such requirement with overloading operator []?

It looks ugly the API user has to do a explicit conversion 'a[int(0)]'...
It looks ugly the API user has to do a explicit conversion 'a[int(0)]'...

The problem can be solved for the user at the cost of some library complexity.

The standard contains a special case that allows literal integers with the value zero to convert to pointers of any type. Some indirection solves the problem:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
struct A {
    // the formal parameter x is never a literal integer
    // no matter what it is bound to  
    template <typename T>
    decltype(auto) operator[](T const& x)
    { return this->subscript(x); }   
    template <typename T>
    decltype(auto) operator[](T const& x) const
    { return this->subscript(x); } 

private:
    A & subscript(const std::string &) {
        std::cout << "string" << std::endl;
        return (*this);
    }
    
    const A & subscript(int) const {
        std::cout << "int" << std::endl;
        return (*this);
    }
};

Last edited on
> is it possible to implement such requirement with overloading operator []?
¿what requirement?
¿why is the string version non-const? it's quite different behaviour for the same named operation.
> is it possible to implement such requirement with overloading operator []?

Normally, overloaded subscript operators come in pairs; one of them being const-qualified.
For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
#include <string>

struct A {

        A& operator[]( const std::string& )
        { std::cout << "string\n" ; return *this ; }

        const A& operator[]( const std::string& ) const
        { std::cout << "string (const)\n" ; return *this ; }

        A& operator[]( int )
        { std::cout << "int\n" ; return *this ; }

        const A& operator[]( int ) const
        { std::cout << "int (const)\n" ; return *this ; }
};

int main() {

    A a ;
    a[0] ; // int
    a["abcd"] ; // string

    const A ca ;
    ca[0] ; // int (const)
    ca["abcd"] ; // string (const)
}

http://coliru.stacked-crooked.com/a/6b46cb5bef97507f
https://rextester.com/GORI17996
Topic archived. No new replies allowed.