Home > OS >  Error in implementation of Matrix multiplication using template classes
Error in implementation of Matrix multiplication using template classes

Time:06-12

I got a homework which looks something like this. I am working on it and hold beginner knowledge of the same. I have to create a header file that contains this code and then use the header file to get the desired results.

I am working with C template, and operator overloading.

#include <iostream>
#include <memory>
#include "matrix.h"
#include "symetric_matrix.h"

using namespace std;

int main()
{
    const Matrix<int, 3, 2> m1; // Creates 3*2 matrix, with all the default elements set to 0;
    cout << m1 << endl;
    Matrix<int, 3, 3> m2(4); // Creates 3*3 matrix, with the default elements equals to 4;
    cout << m2 << endl;
    const Matrix<int, 3, 3> m3 = m2; // C-py constructor may take O(MN) and not O(1).
    cout << m3 << endl;

    // min() returns the minimal value in the matrix.
    if (min(m1) < min(m3))
        cout << "Min value of m3(" << min(m3) << ") is bigger than min value of m1(" << min(m1) << ")" << endl;

    if (m1.avg() < m3.avg()) // Compares the average of the elements
        cout << "Average value of m3(" << m3.avg() << ") is bigger than average value of m1(" << m1.avg() << ")" << endl;

    m2(0, 0) = 13;
    cout << m2[0][0] << " " << m2[1][0] << endl; // Should print "13 4"

    try
    {
        cout << m2   m3 << endl;
        cout << m3 * m1 << endl; // You can choose the format of matrix printing;
        cout << m1 * m2;         // This should throw an exception
    }
    catch (const Matrix<int, 3, 2>::IllegalOperation &e)
    {
        cout << e.what() << endl;
    }

    Matrix<int, 3, 3> m4;
    m4 = m3;
    cout << m4 << endl;
    for (int i = 0; i < 3;   i)
        for (int j = 0; j < 3;   j)
            m4(i, j) = i   j;
    cout << m4 << endl;

    cout << "m4[1][1] = " << m4[1][1] << endl;

    cout << "m4[1][1] = " << m4(1, 1) << endl; // m4(1,1) same result as m4[1][1]

    Matrix<int, 3, 3> m5(3);
    m5 = 2 * m4;
    cout << m5 << endl;
    Matrix<int, 3, 3> m6(m4);
    cout << m6 << endl;
    m5  = m4;
    cout << m5 << endl;

    if (m6 != m5)
        cout << "m6 != m5" << endl;

    Matrix<Matrix<int, 3, 2>, 4, 4> composite(m1); // Creates matrix, where each element is m1;

    cout << composite;

    unique_ptr<Matrix<int, 3, 3>> symetric_matrix(new SymetricMatrix<int, 3>(5)); // SymetricMatrix matrix 3*3 with default element equals to 5;

    (*symetric_matrix)(1, 2) = 8;
    cout << (*symetric_matrix)(1, 2) << " " << (*symetric_matrix)(2, 1) << endl; // Should print "8 8"
    cout << (*symetric_matrix)[1][2] << " " << (*symetric_matrix)[2][1] << endl; // Should print "8 8"

    (*symetric_matrix)[1][0] = 18;
    cout << (*symetric_matrix)[1][0] << " " << (*symetric_matrix)[0][1] << endl; // Should print "18 18"

    return 0;
}

My Updated solution for now.

template <class T, int M, int N>
class Matrix
{
private:
    T mat[M][N];
    int rows = M;
    int cols = N;

public:
    // constructor
    Matrix(int v = 0)
    {
        for (int i = 0; i < M; i  )
        {
            for (int j = 0; j < N; j  )
                mat[i][j] = v;
        }
    }

    T &operator()(int i, int j)
    {
        return mat[i][j];
    };

    T *operator[](int index)
    {
        return mat[index];
    };

    // << overloading
    friend std::ostream &operator<<(std::ostream &os, const Matrix<T, M, N> &L)
    {
        for (int i = 0; i < M; i  )
        {
            for (int j = 0; j < N; j  )
                os << L.mat[i][j] << " ";
            os << "\n";
        }
        return os;
    };

    template <class T1, int M1, int N1>
    Matrix<T, M, M> operator*(Matrix<T1, M1, N1> const &other);
    Matrix<T, M, M> operator (Matrix<T, M, N> const &other);

    friend T min(Matrix obj)
    {
        T result = obj.mat[0][0];
        for (int i = 0; i < M; i  )
        {
            for (int j = 0; j < N; j  )
                if (result < obj.mat[i][j])
                    result = obj.mat[i][j];
        }
        return result;
    };

    long double avg() const
    {
        long double result = 0;
        for (int i = 0; i < M; i  )
        {
            for (int j = 0; j < N; j  )
                if (result < mat[i][j])
                    result = result   mat[i][j];
        }
        return result / (M * N);
    }
};

template <class T, int M, int N>
Matrix<T, M, M> Matrix<T, M, N>::operator (Matrix const &other)
{
    if ((this->rows == other.rows) && (this->cols == other.cols))
    {
        Matrix<T, M, N> resultantMatrix;

        for (auto i = 0; i < this->rows; i  )
        {
            for (auto j = 0; j < this->cols; j  )
            {
                auto &valueFirst = this->mat[i][j];
                auto &valueSecond = other.mat[i][j];

                // if ((additionOverflow(valueFirst, valueSecond)) || (additionUnderflow(valueFirst, valueSecond)))
                //     throw std::out_of_range("Resultant value of matrix is out of range");
                // else
                resultantMatrix(i, j) = valueFirst   valueSecond;
            }
        }
        return resultantMatrix;
    }
    else
        throw std::runtime_error("Matrices cannot be added, sizes do not match");
}

template <class T, int M, int N>
template <class T1, int M1, int N1>
Matrix<T, M, M> Matrix<T, M, N>::operator*(Matrix<T1, M1, N1> const &other)
{
    if ((this->rows == other.rows) && (this->cols == other.cols))
    {
        Matrix<T, M, N> resultantMatrix;

        for (auto i = 0; i < this->rows; i  )
        {
            for (auto j = 0; j < this->cols; j  )
            {
                for (auto k = 0; k < this->cols; k  )
                {
                    auto &valueFirst = this->mat[i][k];
                    auto &valueSecond = other(k, j);

                    // if ((additionOverflow(valueFirst, valueSecond)) || (additionUnderflow(valueFirst, valueSecond)))
                    //     throw std::out_of_range("Resultant value of matrix is out of range");
                    // else
                    resultantMatrix(i, j)  = valueFirst * valueSecond;
                }
            }
        }
        return resultantMatrix;
    }
    else
        throw std::runtime_error("Matrices cannot be added, sizes do not match");
}

I am getting an error and I don't understand why.

error: no match for call to ‘(const Matrix<int, 3, 2>) (int&, int&)’
  112 |                     auto &valueSecond = other(k, j);
      |                                         ~~~~~^~~~~~
matrix.h:20:8: note: candidate: ‘T& Matrix<T, M, N>::operator()(int, int) [with T = int; int M = 3; int N = 2]’ (near match)
   20 |     T &operator()(int i, int j)
      |        ^~~~~~~~
matrix.h:20:8: note:   passing ‘const Matrix<int, 3, 2>*’ as ‘this’ argument discards qualifiers

It only happens at this line auto &valueSecond = other(k, j); and not this one resultantMatrix(i, j) = valueFirst * valueSecond;, Why?

I just need help with the whole program while I try and learn! Any help is appreciated.

CodePudding user response:

As for the error message

matrix.h:20:8: note:   passing ‘const Matrix<int, 3, 2>*’ as ‘this’ argument discards qualifiers

other is const Matrix<int, 3, 2>&. The T &operator()(int i, int j) is implemented for non const Matrix<int, 3, 2>&. There should be provided two versions of the operators

T &operator()(int i, int j)
{
    return mat[i][j];
};
const T &operator()(int i, int j) const
{
    return mat[i][j];
};

T *operator[](int index)
{
    return mat[index];
};
const T *operator[](int index) const
{
    return mat[index];
};

Using operator() as a subscript operator may be confusing. It should be

T &operator[](int i, int j)
{
    return mat[i][j];
};
const T &operator[](int i, int j) const
{
    return mat[i][j];
};

Subscript operators usually are defined for size_t types.

  •  Tags:  
  • c
  • Related