-1

I have a template array class overloading both operator [] to access items and operator T * to get direct buffer access.

template< typename T > class buffer
{
    const T & operator [] ( size_t ) const;
          T & operator [] ( size_t );

    operator const T * () const;
    operator       T * ();
};

For some reason, using operator [] on an instance of this class generates a compilation error saying that there is 4 possible overloads.

buffer< int > buf;
buf[ some_position ] = 0; // Generates an error

Error :

Error   3   error C2666: 'XXX::buffer<T>::operator []' : 4 overloads have similar conversions   c:\XXX.cpp  3886

Is the operator [] trying to convert my instance buf to a T * ? Why are 4 overloads detected instead of 2 ? Thank you. :)

EDIT : Actually it is : buf[ some_position ] = 0; // Generates an error

Virus721
  • 8,061
  • 12
  • 67
  • 123

2 Answers2

1

The Problem you are having is that operator T* and operator[] both will allow buf[some_position] to be valid. In your code T* is an int* and int* has an [] overload.

You can see that with this live example

I think this might be an issue with you VS as running the code on Coliru and ideone with some modifications to get it to run both give working code.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • Btw, g++ lists only 2 candidates, and OP's compiler (VS2005) says four. Is it just that OP has outdated Visual Studio? – Petr Jun 19 '15 at 14:23
  • Yeah I am going to code with a VS problem. [Coliru](http://coliru.stacked-crooked.com/a/c938150606e84349) doesn't mind it. – NathanOliver Jun 19 '15 at 14:28
  • That's only part of the issue, as there needs to be ambiguous implicit conversions for the call to be ambiguous. – TartanLlama Jun 19 '15 at 14:33
  • Thanks for your answer. I've updated my question, i forgot the assignment, so it wasn't about a const / not-const, but what TartanLlama said. – Virus721 Jun 19 '15 at 14:38
1

The issue is that you have implicit conversions going in both directions.

Disregarding const, your two candidates are:

T & buffer::operator [] ( size_t );
int& operator[] (int*, int);

For the call buf[pos] where pos is an int (such as a literal), the call is ambiguous. The first candidate could be selected by converting pos to a std::size_t and the second could be selected by converting buf to int*.

You could disambiguate this call by explicitly casting the argument to a std::size_t, or modifying the operator to take an int instead.

TartanLlama
  • 63,752
  • 13
  • 157
  • 193
  • Thanks, i didn't know about `int& operator[] (int*, int);` I guess it is a non-member operator casting the object using its `operator T *` ? – Virus721 Jun 19 '15 at 14:34
  • It's just the built-in operation for indexing an integer pointer as an array. The compiler checks that because of your implicit conversion operator to `T*`. – TartanLlama Jun 19 '15 at 14:36
  • I assume that i should avoid coupling these two overloads and use a named method to access the buffer instead, shouldn't it ? Like std::vector – Virus721 Jun 19 '15 at 14:39
  • That's certainly a good option if it fits with your use-cases. – TartanLlama Jun 19 '15 at 14:40