赋值-数组的左操作数需要左值

lvalue required as left operand of assignment - Array

本文关键字:操作数 赋值 数组      更新时间:2023-10-16

下面是错误所在的代码片段,行

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

返回错误

赋值的左操作数所需的左值

我找不到适用于数组的答案,我的矩阵定义如下:

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;
}

这是接线员[]我如何通过参考返回

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]);
    }
}

错误实际上是"赋值的左操作数需要左值"。

这意味着您的a[i][j]正在为您提供一个临时对象。当您按值从函数返回时,就会发生这种情况。按值返回的函数调用是右值表达式,并且不能将右值表达式用作赋值的左操作数。您需要更改MatrixMatrix::operator[]返回的helper类上operator[]的实现,以便它们通过引用返回。通过引用返回的函数调用是一个左值表达式,并允许您为其赋值

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

当然,这是有道理的。如果您的operator[]没有通过引用返回,那么分配给它们返回的值会对Matrix的内容产生什么影响?


回应您的编辑:

你的课设计有问题。Matrix类似乎存储一个称为coords的3乘3的float数组。但是,当使用Matrix::operator[]时,它会将coords的一行中的值复制到Vector对象中。它们是副本。然后按值返回Vector,该值将Vector及其包含的值复制到函数之外。对返回的Vector所做的任何操作都只会影响该副本。

除此之外,您的switch语句完全没有意义。每个案例都完全相同。你只需要使用i作为数组索引,而不需要打开它

此外,如果要允许调用operator[]的人修改Matrix的内容,则operator[]函数不能是const

有几个替代方案可以解决你的问题。第一种是只返回一个float*,然后用Vector:取消您的计划

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

这是一个非常简单的解决方案,但确实需要传递一个原始指针。原始指针可以像数组一样使用,允许使用语法m[i][j]

您可以执行与Eigen库相同的操作,而是提供一个operator(),它接受两个参数,行索引和列索引:

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

请注意,float是通过引用返回的:float&。这意味着它可以在对operator()的调用之外进行修改。在这里,您可以使用m(i, j)对行和列进行索引。

这意味着您的[]运算符返回的值没有不能用于赋值的地址。它笔直向前。

什么是Vector

问题可能始于什么Matrix::operator[]退货。为了使[][]语法正常工作,它必须返回一些可以应用第二个[]的代理类型,并且将返回对矩阵中所需元素的引用。做这件事的通常方法(至少对我来说)是定义Matrix:中的"setter"answers"getter"

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 ) ];
}

然后使用两个代理(矩阵中的嵌套类):

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 );
}

在实践中,您还希望返回const变量通过CCD_ 36。当然,CCD_ 37不需要CCD_ 38的过载;这个隐式转换就足够了。

在不明显的情况下,Matrix::getIndex做边界检查,然后计算基础中的实际索引包含数据的CCD_ 40。

由于您返回了一个新构建的Vector对象来表示一列(或行,这并不重要),因此此Vector负责更新原始Matrix实例中的一个条目,这有点棘手,但很容易解决:

您必须实现另一个VectorRef类,它不通过值而是通过引用来表示向量,因此可以用于访问lvalues的组件。这意味着,它不包含作为值的数字,而是作为引用,并在构造函数中接受这些引用。为了保持简单,您可以使用指向第一个组件(后面是其他组件)的指针:

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

然后,在矩阵的operator[]中构造这样一个"参考对象":

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

要将VectorRef也用作Vector,请提供转换运算符:

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

这应该会让事情看起来毫无意义。

或者,如果您总是访问矩阵中的元素,而不是整个列,只需直接在矩阵的operator[]中返回列指针:

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

写入mat[x][y]时,这将首先访问具有mat[x]的浮点指针,然后访问该列的第y个元素,该元素是左值