简体   繁体   中英

Matrix Multiplication using Templates in c++

I am trying to use class templates to matrices. But I have run into a problem with matrix multiplication.

template<typename T, unsigned int N, unsigned int M>
class Matrix : public MatrixBase<Matrix<T, N, M>, T, N, M> {

    template<unsigned int K>
    friend Matrix<T, N, K> operator*(const Matrix<T, N, M>& m1, const Matrix<T, M, K>& m2) {
        Matrix<T, N, K> ret;
        for (unsigned int n = 0; n != N; n++) {
            for (unsigned int k = 0; k != K; k++) {
                ret.i[n][k] = 0;
                for (unsigned int m = 0; m != M; m++) {
                    ret.i[n][k] += m1.i[n][m]*m2.i[m][k];
                }
            }
        }
        return ret;
    }
};

When it then comes to multiplying two mat4's(4x4 matrices), like so:

m_model = (m_view*m_model);

It gives the error Invalid operands to binary expression ('mat4' (aka 'Matrix<float, 4, 4>') and 'mat4') . Having had a look online I can see this is not the intended use of function templates, as you have to assign on call the template arguments. Is there a way around this similar to what I first intended, ie automatic assignment of the template argument based on the second argument of the function?

Here are the definitions of MatrixBase and Matrix(aka mat4) respectively:

MatrixBase

template<typename T , unsigned int M>
struct ComponentColumn{
    T& operator[](int m) {
        return i[m];
    }

    const T& operator[](int m) const {
        return i[m];
    }


    T i[M];
};


//-----------MATRIXBASE-----------
template <typename ChildT, typename T, unsigned int N, unsigned int M>
class MatrixBase {
public:
    MatrixBase() {}

    MatrixBase<ChildT, T, N, M> operator*=(const MatrixBase<ChildT, T, N, M>& m1) {
        MatrixBase<ChildT, T, N, M> ret;
        for (unsigned int n = 0; n != N; n++) {
            for (int k = 0; k != M; k++) {
                ret.i[n][k] = 0;
                for (unsigned int m = 0; m != M; m++) {
                    ret.i[n][k] += (*this).i[n][m]*m1.i[m][k];
                }
            }
        }

        *this = ret;

        return ret;
    }

    MatrixBase<ChildT, T, N, M> operator+(const MatrixBase<ChildT, T, N, M>& m1) {
        MatrixBase<ChildT, T, N, M> ret;
        for (int n = 0; n != N; n++) {
            for (int m = 0; m != M; m++) {
                ret.i[n][m] = i[n][m];
            }
        }
        return ret;
    }

    ComponentColumn<T, M>& operator[](int n) {
        return this->i[n];
    }


    const ComponentColumn<T, M>& operator[](int n) const {
        return this->i[n];
    }

    explicit operator T*() {
        return &(*this)[0][0];
    }

protected:
    ComponentColumn<T, M> i[N];
};

mat4

template<typename T>
class Matrix<T, 4, 4> : public MatrixBase<Matrix<T, 4, 4>, T, 4, 4> {
public:
    Matrix<T, 4, 4>() {
        for (unsigned int n = 0; n != 4; n++) {
            for (unsigned int m = 0; m != 4; m++) {
                if (n == m) {
                    (*this)[n][m] = 1;
                } else {
                    (*this)[n][m] = 0;
                }
            }
        }
    }

    Matrix<T, 4, 4>(const Matrix<T, 3, 3>& m) {
        (*this)[0][0] = m[0][0]; (*this)[1][0] = m[1][0]; (*this)[2][0] = m[2][0]; (*this)[3][0] = 0;
        (*this)[0][1] = m[0][1]; (*this)[1][1] = m[1][1]; (*this)[2][1] = m[2][1]; (*this)[3][1] = 0;
        (*this)[0][2] = m[0][2]; (*this)[1][2] = m[1][2]; (*this)[2][2] = m[2][2]; (*this)[3][2] = 0;
        (*this)[0][3] = 0; (*this)[1][3] = 0; (*this)[2][3] = 0; (*this)[3][3] = 1;
    }

    static Matrix<T, 4, 4> Translate(T x, T y, T z);
    static Matrix<T, 4, 4> Translate(const vec3& v);
    static Matrix<T, 4, 4> Scale(T s);
    static Matrix<T, 4, 4> Rotate(T degrees);
    static Matrix<T, 4, 4> Frustum(T left, T right, T bottom, T top, T near, T far);

    explicit operator Matrix<T, 3, 3>() {
        Matrix<T, 3, 3> ret;
        for (int n = 0; n != 3; n++) {
            for (int m = 0; m != 3; m++) {
                ret[n][m] = (*this)[n][m];
            }
        }

        return ret;
    }

    Matrix<T, 4, 4> Transpose() {
        Matrix<T, 4, 4> ret = Matrix<T, 4, 4>();
        for (unsigned int n = 0; n != 4; n++) {
            for (unsigned int m = 0; m != 4; m++) {
                ret.i[n][m] = this->i[m][n];
            }
        }
        *this = ret;
        return ret;
    }

    Matrix<T, 4, 4> Inverse();
};

Unless you are doing this for practice, which would be a good exercise, I would just use an existing linear algebra library which implements matrix vector operations. Such as Armadillo: http://arma.sourceforge.net/

Not an answer, but to share what worked for me and assure the correctness of the method of defining the multiplication operator:

template<typename T, unsigned int N, unsigned int M>
class Matrix {
public:
  template<unsigned int K>
  friend Matrix<T, N, K> operator*(const Matrix<T, N, M>& m1, const Matrix<T, M, K>& m2) {
    Matrix<T, N, K> ret;
    for (unsigned int n = 0; n != N; n++) {
      for (unsigned int k = 0; k != K; k++) {
        ret.i[n][k] = 0;
        for (unsigned int m = 0; m != M; m++) {
          ret.i[n][k] += m1.i[n][m] * m2.i[m][k];
        }
      }
    }
    return ret;
  }
  array<array<T, M>, N> i;
};

int main() {
  Matrix<float, 4, 6> m1; Matrix<float, 6, 10> m2;
  auto m3 = (m1 * m2);
  cout << m3.i[0][0] << m3.i[3][9] << "\n";
  system("pause");
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM