2

I've written a pretty simple array class in C++ and use it in my application:

/* A simple array class template that performs dynamic */
/* memory management and casting to (T*), which allows */
/* to use it as a usual array. */
template <typename T>
class Array
{
public:
    //Constructor
    Array(unsigned long size)
    {
        try
        {
            data = new T[size];
            m_size = size;
        }
        catch(...)
        {
            cout << "Could not allocate " << size << " bytes." << endl;
            data = NULL; m_size = 0;
        }
    }
    //Typecast operator
    operator T*() { assert(data!=NULL); return data; }
    //Subscript operator
    T& operator[] (unsigned long Index);
    //Destructor
    ~Array() { if(data!=NULL) delete[] data; }
private:
    T * data;
    unsigned long m_size;
};

template<typename T>
T& Array<T>::operator[] (unsigned long Index)
{
    assert(Index<m_size);
    assert(data!=NULL);
    return data[Index];
}

However, when I use it like this:

Array<char> filename(5);
filename[0] = SomeVar;

GCC ouputs the following warning:

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]
note: candidate 1: T& Array<T>::operator[](long unsigned int) [with T = char]
note: candidate 2: operator[](char*, int) <built-in>

What is the reason? How can I solve it?

Ilya
  • 728
  • 2
  • 8
  • 22

1 Answers1

2

The reason is quite simple: for your filename[0] the compiler can use your operator[], or it can convert filename to char* using your type conversion operator, and then apply operator[] to a char pointer.

More explicitly, what happening is

filename.Array<char>::operator[](0)

vs

filename.Array<char>::operator char*().operator[](0)

(don't know whether the latter is correct c++, but it gives an idea of what happening)

P.S. Almost sure this should have been asked before, but was not able to find a duplicate.

Petr
  • 9,812
  • 1
  • 28
  • 52
  • `operator T*() { assert(data!=NULL); return data; }` seems to be the reversed conversion of constructor `Array( T * p){ data = p};`? – Shindou Jul 23 '15 at 10:36
  • Oh, I see! Can I remove the subscipt operator? – Ilya Jul 23 '15 at 10:36
  • @Ilya use explicit conversion operators. See [this](http://stackoverflow.com/questions/4421706/operator-overloading?rq=1) – Shindou Jul 23 '15 at 10:38
  • @Ilya It seems that by `operator T*() { assert(data!=NULL); return data; }` is to convert a `Array` to `T*`, and by `Array( T * p){ data = p;}` is a `T*` to a `Array`. And use `explicit` would prevent the implicit conversion. – Shindou Jul 23 '15 at 10:41
  • No, operator T* returns Array.data, and I don't see where you have found the Array(T* p) constructor. – Ilya Jul 23 '15 at 10:47
  • And even if it existed, what's the problem? – Ilya Jul 23 '15 at 10:48