以下是错误所在的代码片段,
行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]);
}
}
答案 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];
}
请注意,引用返回float
:float&
。这意味着可以在调用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
个元素,这是左值