views:

52

answers:

2

I'm implementing a simple C++ grid class. One Function it should support is accessed through round brackets, so that I can access the elements by writing mygrid(0,0). I overloaded the () operator and i am getting the error message: "non-lvalue in assignment".

what I want to be able to do:

//main

cGrid<cA*> grid(5, 5);

grid(0,0) = new cA();

excerpt of my implementation of the grid class:

template class cGrid {

private:
    T* data;
    int mWidth;
    int mHeight;

public:
    cGrid(int width, int height) : mWidth(width), mHeight(height) { 
        data = new T[width*height]; 
    }

    ~cGrid() { delete data; }

    T operator ()(int x, int y)
    {
        if (x >= 0 && x <= mWidth) {
            if (y >= 0 && y <= mHeight) {
                return data[x + y * mWidth];
            }
        }
    }


    const T &operator ()(int x, int y) const
    {
        if (x >= 0 && x <= mWidth) {
            if (y >= 0 && y <= mHeight) {
                return data[x + y * mWidth];
            }
        }
    }

The rest of the code deals with the implementation of an iterator and should not be releveant.

A: 

What does this template:

 T &operator ()(int x, int y) const
{
    if (x >= 0 && x <= mWidth) {
        if (y >= 0 && y <= mHeight) {
            return data[x + y * mWidth];
        }
    }
}

do if x & y are out of range? You should raise an exception. And how are you allocating memory to the grid in the constructor? As regards constness, you need to supply two versions of this operator - a const one that returns a const reference, and a non-const one that returns a non-const reference.

Edit: You also have an off-by one error in the operator. This compiles and runs:

template <typename T>
struct Grid {
    Grid( int x, int y ) : mX(x), mY(y), mData(0) {
      mData = new T[ x * y ];
    }

    ~Grid() {
      delete [] mData;
    }

    T &operator ()(int x, int y)  {
        if (x >= 0 && x < mX) {
            if (y >= 0 && y < mY) {
                return mData[x + y * mX];
            }
        }
    throw "out of range" ;;
    }

    int mX, mY
    T * mData;
};


int main() {
    Grid <int> g(2,3);
    g(0,0) = 42;
}
anon
Allocation of the grid: private: T* data; public: cGrid(int width, int height) : mWidth(width), mHeight(height) { data = new T[width*height]; }And yes, I really should raise an exception. ty
Tyrfing
Decent compilers would warn you about the existence of execution paths exiting the function without returning a value (for functions with return values).
Ari
Thanks its all working now
Tyrfing
@Ari In fact, g++ with -Wall does exactly that.
anon
I have -Wall now turned on as well.
Tyrfing
A: 

As Bill remarked, the operator shouldn't be const. I believe this is the reason for the compilation error (even if the error reported seems different). The compiler only encounters the error at the assignment line because it is a template class.

To be clear, you can't have a const method return a reference to a non-const. I.e., the problem is that the declaration T &operator... const is illegal. It should be either T &operator... or const T &operator... const. Of course you can have both.

Edit: Removing the const doesn't help because now both methods have the same signature (the return type is not considered part of the signature for purposes of resolving the call). The method being called is the one returning T, not T &. Get rid of it (or replace it with a const method returning a const reference.)

Ari
Tyrfing
got it working, thanks.
Tyrfing