lvalue required as left operand of assignment - Array

為{幸葍}努か 提交于 2020-01-24 00:29:07

问题


Below is the snippet of code where the error lies, the line

a[i][j] = m[i][j] + w[i][j];

returns an error

lvalue required as left operand of assignment

I can't find an answer that applies to arrays, my Matrix is defined as follows:

Matrix::Matrix() {
    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
            coords[i][j] = 0.0f;
}

const Matrix operator+(const Matrix &m, const Matrix &w) {
    Matrix a;
    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 4 ; j++)
            a[i][j] = m[i][j] + w[i][j];  // <----- error
    return a;
}

Here is the operator[] How do I return by reference

const Vector Matrix::operator[](int i) const{
    switch(i)
    {
    case 0: return Vector (coords[i][0], coords[i][1], coords[i][2]);
    case 1: return Vector (coords[i][0], coords[i][1], coords[i][2]);
    case 2: return Vector (coords[i][0], coords[i][1], coords[i][2]);
    }
}

回答1:


The error is actually "lvalue required as left operand of assignment".

It means that your a[i][j] is giving you a temporary object. This happens when you return from a function by value. A function call that returns by value is an rvalue expression, and you cannot use an rvalue expression as the left operand of an assignment. You need to change the implementation of operator[] on both the Matrix and the helper class that Matrix::operator[] returns so that they return by reference. A function call that returns by reference is an lvalue expression and will allow you to assign to it.

template <typename T>
Vector<T>& Matrix<T>::operator[](int index) { ... }
template <typename T>
T& Vector<T>::operator[](int index) { ... }

Of course, this makes sense. If your operator[]s didn't return by reference, how would assigning to the value returned by them have any effect on the contents of the Matrix?


In response to your edit:

You have a problem with the design of your class. The Matrix class appears to store a 3-by-3 array of floats called coords. However, when you use Matrix::operator[], it copies the values from a row of coords into a Vector object. They are copies. You then return that Vector by value, which copies the Vector and its contained values out of the function. Anything you do to that returned Vector will only affect that copy.

In addition to this, your switch statement is totally pointless. Every case is exactly the same. You just need to use i as the array indices and not switch on it.

Also, if you're going to allow people that call operator[] to modify the contents of your Matrix, then the operator[] function must not be const.

There are a few alternatives that will fix your problem. The first is to just return a float* instead and scrap your plan with Vector:

float* Matrix::operator[](int i) {
    return coords[i];
}

That's a very simple solution but does involve passing a raw pointer around. The raw pointer can be used like an array, allowing you the syntax m[i][j].

You could do the same as the Eigen library and instead provide a operator() that takes two arguments, the row index and column index:

float& Matrix::operator()(int i, int j) {
    return coords[i][j];
}

Note that the float is being returned by reference: float&. This means that is modifiable from outside the call to operator(). Here, you would index a row and column with m(i, j).




回答2:


it means your [] operator returns a value without an address that cannot be used for assignment. Its straight forward.




回答3:


What is Vector?

The problem probably starts with what Matrix::operator[] returns. For the [][] syntax to work, it must return some sort of proxy, to which the second [] can be applied, and it will return a reference to the desired element in the matrix. The usual way of doing this (at least for me) is to define a "setter" and "getter" in Matrix:

void set( int i, int j, double new_value )
{
    myData[ getIndex( i, j ) ] = new_value;
}

double get( int i, int j ) const
{
    return myData[ getIndex( i, j ) ];
}

and then make use of two proxies (nested classes in Matrix):

class Proxy2D
{
    Matrix* myOwner;
    int myIndex1;
    int myIndex2;
public:
    Proxy2D( Matrix& owner, int index1, int index2 )
        : myOwner( &owner )
        , myIndex1( index1 )
        , myIndex2( index2 )
    {
    }
    void operator=( double new_value ) const
    {
        myOwner->set( myIndex1, myIndex2, new_value ):
    }
    operator double() const
    {
        return myOwner->get( myIndex1, myIndex2 );
    }
};

class Proxy1D
{
    Matrix* myOwner;
    int myIndex;
public:
    Proxy1D( Matrix& owner, int index )
        : myOwner( &owner )
        , myIndex( index )
    {
    }
    Proxy2D operator[]( int index2 ) const
    {
        return Proxy2D( *myOwner, myIndex, index2 );
    }
};

Proxy1D operator[]( int index1 )
{
    return Proxy1D( *this, index1 );
}

In practice, you'll want const variants as well, to be returned by operator[]( int index1 ) const. And of course, ConstProxy2D won't need the overload for operator=; the implicit conversion is sufficient.

And in case it isn't obvious, Matrix::getIndex does the bounds checking, and then calculates the actual index in the underlying std::vector<double> which contains the data.




回答4:


Since you return a newly constructed Vector object to represent a column (or row, doesn't really matter), this Vector is responsible to update an entry in the original Matrix instance, which is a little bit tricky but can easily be solved:

You have to implement another VectorRef class which doesn't represent a vector by value but by reference and can thus be used to access the components as lvalues. This means, that it doesn't contain the numbers as values but as reference and takes these references in its constructor. To keep things simple, you can use a pointer which points to the first component (followed by the other components):

class VectorRef {
    float *coords;
public:
    VectorRef(float *coords) : coords(coords) {}
    float & operator[](int i) { return coords[i]; }
};

Then, construct such a "reference object" in the operator[] of the matrix:

VectorRef Matrix::operator[](int i) {
    return VectorRef (coords[i]);
}

To use the VectorRef also as a Vector, provide a conversion operator:

    // (within VectorRef:)
    operator Vector() const { return Vector(coords[0], coords[1], coords[2]); }

This should make things seemless.

Alternatively, if you always access the elements within a matrix and not columns as a whole, just return the column pointer directly in the operator[] of the matrix:

float * Matrix::operator[](int i) {
    return coords[i];
}

When writing mat[x][y], this will first access the float pointer with mat[x] and then accesses the y-th element of that column, which is an lvalue.



来源:https://stackoverflow.com/questions/14832847/lvalue-required-as-left-operand-of-assignment-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!