左值作为赋值的左操作数 - 数组

时间:2013-02-12 12:42:31

标签: c++ arrays operator-overloading

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

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

返回错误

  

左值作为赋值的左操作数

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

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

4 个答案:

答案 0 :(得分:10)

该错误实际上是“左值作为分配的左操作数”。

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

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

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


回复您的修改:

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

除此之外,您的switch声明完全没有意义。每个案例都完全一样。您只需要使用i作为数组索引而不是打开它。

此外,如果您允许致电operator[]的人修改Matrix的内容,则operator[]功能不得为const。< / p>

有一些替代方案可以解决您的问题。第一种方法是返回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];
}

请注意,引用返回floatfloat&。这意味着可以在调用operator()之外修改。在这里,您可以使用m(i, j)索引行和列。

答案 1 :(得分:1)

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

答案 2 :(得分:1)

什么是Vector

问题可能始于Matrix::operator[] 回报。要使[][]语法起作用,必须返回一些语法 可以应用第二个[]的代理类型,以及它 将返回对矩阵中所需元素的引用。 这样做的常用方法(至少对我而言)是定义 Matrix中的“setter”和“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 ) ];
}

然后使用两个代理(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 );
}

在实践中,您还需要返回const变体 按operator[]( int index1 ) const。而且当然, ConstProxy2D不需要重载operator=;该 隐式转换就足够了。

如果不明显,Matrix::getIndex可以完成限制 检查,然后计算底层的实际索引 std::vector<double>包含数据。

答案 3 :(得分:0)

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

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

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个元素,这是左值