2

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

Tom
  • 1,027
  • 2
  • 16
  • 35
  • 1
    Why not http://stackoverflow.com/questions/12375591/vector-of-vectors-to-create-matrix ? – kotlomoy Jun 18 '13 at 19:53
  • Thank you for you reply. I have already implemented the whole matrix class, so I think don't need vectors from STL – Tom Jun 18 '13 at 20:06
  • 1
    Then you can make your Matrix to be Vector4 of Vector4's. Then this problem will be solved automatically. – kotlomoy Jun 18 '13 at 20:10
  • Oh I see, maybe that's not a stupid idea... but it needs many alterations in my code – Tom Jun 18 '13 at 20:15
  • 2
    @Tom A vector of vectors can work but would become a problem if you need a function that returns a column or diagonal instead of a row. – TractorPulledPork Jun 18 '13 at 20:26
  • 1
    @Tom The first `operator()` is called because you call it on a non-`const` object. In other words because `m` is declared non-`const`. But why don't you just use an existing linear algebra library? For example [Armadillo](http://arma.sourceforge.net/) which, AFAIK, has heavily optimized small vectors and matrices. – Ali Jun 19 '13 at 21:08
  • @Ali I see it now... was bad thinking the whole time. Thank you for your explanation. I know that there are some libraries, but I'd like to make my own (I'm know that's stupid :). Again thank you, now everything become clear :) – Tom Jun 19 '13 at 21:48
  • @Ali I would be grateful if you say something about my solution :) – Tom Jun 20 '13 at 14:21
  • 1
    @Tom Please consider posting your code to http://codereview.stackexchange.com/ . If I were you, I would either do the deep copy of the row and live with the consequences (simple code, slower program) or would use and existing linear algebra library if performance is important. – Ali Jun 20 '13 at 16:58

1 Answers1

2

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.

  • Thank you, actually I don't really understand you, but I will be trying to code that – Tom Jun 18 '13 at 20:07
  • 1
    @Tom This might help: http://en.wikipedia.org/wiki/Value_(computer_science) If you have any specific questions I could try to answer them. – TractorPulledPork Jun 18 '13 at 20:15
  • I'm still having problems to implement that. How to make a reference to an object if object is unknown at the time when reference needs to be initialized? – Tom Jun 19 '13 at 11:33
  • 1
    @Tom You're right, it is much simpler storing pointers. Here's an example of what I was thinking: http://pastebin.com/YXmqd8HR – TractorPulledPork Jun 19 '13 at 13:51
  • I think your solution is better, but now I have mind blown :) – Tom Jun 19 '13 at 14:25