Tom
Tom

Reputation: 1057

Getting vector from matrix by overloading subscript operator()

I want to do something like this:

Matrix m;    // (4x4 matrix)
Vector4 v;   // (4-elements vector)

m(0) = v;    // replace first 4-elements matrix row by vector v
v = m(0);    // replace vector v by first 4-elements matrix row

heres my code:

Vector4& Matrix::operator() (unsigned row)
{
    return Vector4(mat[row][0], mat[row][1], mat[row][2], mat[row][3]);
}

Vector4 Matrix::operator() (unsigned row) const
{
    return Vector4(mat[row][0], mat[row][1], mat[row][2], mat[row][3]);
}

the second operator works fine, but when I try to compile first one, I get this error:

error: invalid initialization of non-const reference of type ‘Vector4&’ from an rvalue of type ‘Vector4’

So where is the problem? It's good idea to overload operator() instead of operator[] in this case?

By getting only one element from matrix I use the other two operators:

float& Matrix::operator() (unsigned row, unsigned col)
{
    return mat[row][col];
}

float Matrix::operator() (unsigned row, unsigned col) const
{
    return mat[row][col];
}

Edit 1 (almost solution)

I think I found some solution. The first operator has been replaced to:

Matrix::MatrixHelper operator() (unsigned row)
{
    MatrixHelper m;
    m.f1 = &mat[row][0];
    m.f2 = &mat[row][1];
    m.f3 = &mat[row][2];
    m.f4 = &mat[row][3];

    return m;
}

heres the definition of MatrixHelper class:

class MatrixHelper
{
    public:

    friend class Matrix;

    void operator= (const Vector4& v)
    {
        *f1 = v.x;
        *f2 = v.y;
        *f3 = v.z;
        *f4 = v.w;
    }

    private:

    float* f1;
    float* f2;
    float* f3;
    float* f4;
};

now is possible to do something like that:

m(0) = Vector4(3,3,3,3);

but then occurs new problem, when calling this:

(m)(0) * someScalar;

the second operator is never called, so I have to implement them in my MatrixHelper class right? I'm on the right track?

Edit 2

OK this problem would be solved if the two operators would be working at the same time. But now only one of them can be enabled. I can not understand why always is working the first operator, for example having this code (just example):

Vector4& Matrix::operator() (unsigned row)
{
    std::cout << "Operator one is working now\n";
}

Vector4 Matrix::operator() (unsigned row) const
{
    std::cout << "Operator two is working now\n";
}

No matter if I am doing

m(0) = Vector(4,4,4,4)

or

Vector4 v = m(0)

always is working the first operator. Why?

Edit 3 (Solution)

I have found some other solution. Now all it's working, but performance may be a little problem. Solution not resolved in the way I wanted and it is a little far-fetched. Here's the code:

Operators:

Vector4 Matrix::operator() (unsigned row)
{
    return Vector4 (&mat[row][0], &mat[row][1], &mat[row][2], &mat[row][3]);
}

Vector4 Matrix::operator() (unsigned row) const
{
    return Vector4 (mat[row][0], mat[row][1], mat[row][2], mat[row][3]);
}

as you can see the first operator returns a vector that takes pointers. The hard work happens now in Vector4 class instead of Matrix. Vector4 has now an extra constructor:

Vector4(float* x, float* y, float* z, float* w)
{
    this->px = x; this->py = y; this->pz = z; this->pw = w;
    this->x = *x; this->y = *y; this->z = *z; this->w = *w;
    pointer = true;
}

first line are pointers, second - variables, and third line is a boolean type variable witch means what constructor has been called (normal or pointers).

Now comes the last operator (operator=):

Vector4 operator= ( const Vector4& v)
{
    if ( pointer )
    {
        *px = x = v.x;
        *py = y = v.y;
        *pz = z = v.z;
        *pw = w = v.w;
    }
    else
    {
        x = v.x;
        y = v.y;
        z = v.z;
        w = v.w;
    }
}

If pointer is true that means - px, py, pz and pw are pointers to some row elements in matrix, and we have to change them. Else - just normal vector.

So now question... it is bad bad solution, or just bad? :D

Upvotes: 2

Views: 834

Answers (1)

TractorPulledPork
TractorPulledPork

Reputation: 793

The Vector4 you are instantiating in the errored code is an r-value which is temporary. Aside from the fact that you can't assign it to a non-const reference, it will be destroyed when your function exits and the return value would be an invalid stack location.

One solution would be to return a different object by value that stores references to the individual elements you need and allows you to act upon them in a transparent way.

Upvotes: 2

Related Questions