Matrix Operator*= c++ returns error - c++

Good morning. I been dealing with this error for 3 days now and I can't figure it out. I was tasked to create a header file for a series of matrix tests to learn the use of of templates on c++. I seem to have all other operators working except for operator*=. I am including the header file, plus the error I am getting.
#ifndef MATRIX_H
#define MATRIX_H
#include <vector>
#include <iostream>
#include <math.h>
#include <complex>
using namespace std;
namespace nkumath {
template <typename T, size_t ROWS, size_t COLS>
class Matrix {
friend class Matrix;
public:
Matrix(const T & init = T()) : elts(ROWS, vector<T>(COLS, init)) {
};
const vector<T> & operator[](int ROWS) const {
return elts[ROWS];
}; //not sure if correct
vector<T> & operator[](int ROWS) {
return elts[ROWS];
}; //not sure if correct
//MatrixAdd
Matrix & matrixAdd(const Matrix & lhs, const Matrix & rhs) {
for (int r = 0; r < ROWS; r++) {
for (int c = 0; c < COLS; c++) {
this->elts[r][c] = lhs[r][c] + rhs[r][c];
}
}
return *this;
};
//MatrixSubtract
Matrix & matrixSubtract(const Matrix & lhs, const Matrix & rhs) {
for (int r = 0; r < ROWS; r++) {
for (int c = 0; c < COLS; c++) {
this->elts[r][c] = lhs[r][c] - rhs[r][c];
}
}
return *this;
};
//MatrixMult
template<size_t INNER>
Matrix & matrixMult(const Matrix<T, ROWS, INNER> & mat1, const Matrix<T, INNER, COLS> & mat2) {
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
//elts[i][j] = 0;
for (int k = 0; k < INNER; k++) {
elts[i][j] += mat1.elts[i][k] * mat2.elts[k][j];
}
}
}
return *this;
}; //not done
//print function
void print(ostream & out) const {
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
out << elts[i][j];
}
out << "\n";
}
};
private:
vector< vector<T> > elts;
};
//Note, you have to define each time a template to avoid having the errors
//Operator<<
template <typename T, size_t ROWS, size_t COLS>
ostream & operator<<(ostream & out, const Matrix<T, ROWS, COLS> & elts) {
elts.print(out);
return out;
};
//Operator==
template <typename T, size_t ROWS, size_t COLS>
bool operator==(const Matrix<T, ROWS, COLS> & lhs, const Matrix<T, ROWS, COLS> & rhs) {
return true;
};
//Operator+
template <typename T, size_t ROWS, size_t COLS>
Matrix<T, ROWS, COLS> operator+(const Matrix<T, ROWS, COLS> & lhs, const Matrix<T, ROWS, COLS> & rhs) {
Matrix<T, ROWS, COLS> returnVal;
return returnVal.matrixAdd(lhs, rhs);
};
//Operator-
template <typename T, size_t ROWS, size_t COLS>
Matrix<T, ROWS, COLS> operator-(const Matrix<T, ROWS, COLS> & lhs, const Matrix<T, ROWS, COLS> & rhs) {
Matrix<T, ROWS, COLS> returnVal;
return returnVal.matrixSubtract(lhs, rhs);
};
//Operator*
template <typename T, size_t ROWS, size_t COLS>
Matrix<T, ROWS, COLS> operator*(const Matrix<T, ROWS, COLS> & lhs, const Matrix<T, ROWS, COLS> & rhs) {
Matrix<T, ROWS, COLS> returnVal;
return returnVal.matrixMult(lhs, rhs);
};
//Operator+=
template <typename T, size_t ROWS, size_t COLS, typename C>
Matrix<T, ROWS, COLS> operator+=(Matrix<T, ROWS, COLS> & lhs, const C & rhs) {
//Matrix<T,ROWS,COLS> returnVal;
lhs.matrixAdd(lhs, rhs);
return lhs;
};
//Operator-=
template <typename T, size_t ROWS, size_t COLS, typename C>
Matrix<T, ROWS, COLS> operator-=(Matrix<T, ROWS, COLS> & lhs, const C & rhs) {
lhs.matrixSubtract(lhs, rhs);
return lhs;
};
//Operator*=
template <typename T, size_t ROWS, size_t COLS, typename C>
Matrix<T, ROWS, COLS> operator*=(Matrix<T, ROWS, COLS> & lhs, const C & rhs) {
lhs.matrixMult(lhs, rhs);
return lhs;
};
//Operator/=
template <typename T, size_t ROWS, size_t COLS>
Matrix<T, ROWS, COLS> operator/=(const Matrix<T, ROWS, COLS> & lhs, const int rhs) {
Matrix<T, ROWS, COLS> returnVal(rhs);
for (int r = 0; r < ROWS; r++) {
for (int c = 0; c < COLS; c++) {
returnVal[r][c] = lhs[r][c] / returnVal[r][c];
}
}
return returnVal;
};
//Operator%=
template <typename T, size_t ROWS, size_t COLS>
Matrix<T, ROWS, COLS> operator%=(const Matrix<T, ROWS, COLS> & lhs, const int rhs) {
Matrix<T, ROWS, COLS> returnVal(rhs);
for (int r = 0; r < ROWS; r++) {
for (int c = 0; c < COLS; c++) {
returnVal[r][c] = lhs[r][c] % returnVal[r][c];
}
}
return returnVal;
};
} // namespace Matrix
#endif // MATRIX_H
here is my main.cpp. I am not allowed to change this file....
// main.cpp
// Test driver for Matrix class template project.
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib> // for rand()
#include "Matrix.h"
using namespace std;
using namespace nkumath;
template <typename T, size_t ROWS, size_t COLS>
void randomize(Matrix<T, ROWS, COLS> & mat)
// Put random values in a Matrix.
// Note: It must be possible to assign T an int value.
{
for (size_t i = 0; i < ROWS; i++)
for (size_t j = 0; j < COLS; j++)
mat[i][j] = (rand() % 21) - 10; // Random number in range -10,...,+10
}
struct Complex
{
Complex(double re = 0.0, double im = 0.0) : real(re), imag(im) { }
Complex & operator+=(const Complex & rhs)
{
real += rhs.real;
imag += rhs.imag;
return *this;
}
Complex & operator-=(const Complex & rhs)
{
real -= rhs.real;
imag -= rhs.imag;
return *this;
}
Complex & operator*=(const Complex & rhs)
{
real = real * rhs.real - imag * rhs.imag;
imag = real * rhs.imag + imag * rhs.real;
return *this;
}
double real;
double imag;
};
Complex operator+(const Complex & lhs, const Complex & rhs)
{
return Complex(lhs.real + rhs.real, lhs.imag + rhs.imag);
}
Complex operator-(const Complex & lhs, const Complex & rhs)
{
return Complex(lhs.real - rhs.real, lhs.imag - rhs.imag);
}
Complex operator*(const Complex & lhs, const Complex & rhs)
{
return Complex(lhs.real * rhs.real - lhs.imag * rhs.imag, lhs.real * rhs.imag + lhs.imag * rhs.real);
}
ostream & operator<<(ostream & out, const Complex & c)
{
out << "(" << c.real << " + " << c.imag << "i)";
return out;
}
int main()
{
srand(100);
ofstream out("output.txt");
// Matrix construction, operator[], and printing:
Matrix<int, 4, 5> m1(2);
out << "m1: " << endl;
m1.print(out);
const Matrix<int, 4, 5> m2 = m1;
out << "m2: " << endl << m2;
for (size_t i = 0; i < 4; i++)
m1[i][i] = 5;
out << "m1: " << endl << m1;
// Tests of const correctness:
// m2[0][0] = 0; // This line should not compile.
// m2 += 4; // Neither should this one.
int n = m2[0][0]; // This line should be okay.
// Scalar operation tests:
out << "m1 += 4: " << endl << (m1 += 4);
out << "m1 -= 6: " << endl << (m1 -= 6);
out << "m1 *= 12: " << endl << (m1 *= 12);
out << "m1 /= 2: " << endl << (m1 /= 2);
out << "m1 %= 7: " << endl << (m1 %= 7);
// Matrix addition and subtraction tests:
Matrix<int, 4, 5> m3;
out << "m3: " << endl << m3;
out << "m3.matrixAdd(m1, m2): " << endl << m3.matrixAdd(m1, m2);
out << "m3.matrixSubtract(m1, m2): " << endl << m3.matrixSubtract(m1, m2);
out << "m2 + m1: " << endl << (m2 + m1);
out << "m2 - m1: " << endl << (m2 - m1);
// Matrix multiplication tests:
Matrix<int, 2, 3> m4;
randomize(m4);
out << "m4: " << endl << m4;
Matrix<int, 3, 5> m5;
randomize(m5);
out << "m5: " << endl << m5;
Matrix<int, 2, 5> m6;
out << "m6.matrixMult(m4, m5): " << endl << m6.matrixMult(m4, m5);
Matrix<int, 2, 5> m7;
matrixMult(m4, m5, m7);
out << "m6 == m7: " << (m6 == m7) << endl;
out << "m6 == m4 * m5: " << (m6 == m4 * m5) << endl;
// Matrices of strings:
Matrix<string, 3, 4> m8("Hello");
for (size_t i = 0; i < 3; i++)
m8[i][i] = " Hi";
out << "m8: " << endl << m8 << endl;
Matrix<string, 3, 4> m9(" there!");
out << "m9: " << endl << m9 << endl;
out << "m8 + m9: " << endl << m8 + m9 << endl;
Matrix<string, 4, 5> m10(", Goodbye!");
//out << m8 * m10 << endl; // This line should not compile.
// Matrices of Complex:
Matrix<Complex, 2, 8> m11;
randomize(m11);
Complex c(1, -3);
m11 += c;
out << "m11: " << endl << m11 << endl;
Matrix<Complex, 8, 3> m12;
randomize(m12);
m12 -= c;
out << "m12: " << endl << m12 << endl;
out << "m11 * m12: " << endl << m11 * m12 << endl;
out.close();
}
The error I am getting is
Error 1 error C2784: 'nkumath::Matrix<T,ROWS,COLS> &nkumath::Matrix<T,ROWS,COLS>::matrixMult(const nkumath::Matrix<T,4,INNER> &,const nkumath::Matrix<T,INNER,5> &)' : could not deduce template argument for 'const nkumath::Matrix<T,INNER,5> &' from 'const int' e:\documents and settings\pato\my documents\visual studio 2010\projects\thematrix\thematrix\matrix.h 136
I am using visual studio c++ 2010. I tried to compile the header on linux gcc4 and I goth a whole different set of errors, so I am going to finish this project in windows. Either way just need someone to point me to the right direction, I have been looking at this for too long.
Thank you!
PJ

I have the code compiling in codepad.org here
Is there any question left?

In your main
you were missing the using namespace std and using namespace nkumath declarations
there is a call matrixMult(m4, m5, m7); which cannot resolve. I'm assuming you mean m7 = m4*m5;
It seems like you have incorrectly made a previously static matrixMult (with the meaning of innerproduct) into a member function of Matrix;
Using this as a freestanding static function works:
template<class T, size_t ROWS, size_t INNER, size_t COLS>
static Matrix<T, ROWS, COLS> innerProduct(const Matrix<T, ROWS, INNER> & mat1, const Matrix<T, INNER, COLS> & mat2) {
Matrix<T, ROWS, COLS> result;
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
//elts[i][j] = 0;
for (int k = 0; k < INNER; k++) {
result.elts[i][j] += mat1.elts[i][k] * mat2.elts[k][j];
}
}
}
return result;
} //not done
Update
It means that you should rewrite the matrixMult method like so (using the above static innerProduct helper):
template<size_t OUTER>
Matrix<T, ROWS, OUTER> matrixMult(const Matrix<T, COLS, OUTER> & mat2) const {
return innerProduct(*this , mat2);
}
also adding something like this is probably what you want:
template<class T, size_t ROWS, size_t INNER, size_t COLS>
Matrix<T, ROWS, COLS> operator*(const Matrix<T, ROWS, INNER> & lhs, const Matrix<T, INNER, COLS> & rhs)
{
return innerProduct(lhs, rhs);
}
I haven't bothered fixing the scalar multiplication, but you should get the idea now (if I'm not wasting my time). Good luck
This way the main.cpp can stay as it was... capice?
This is my resulting Matrix class definition for your perusal:
namespace nkumath {
template <typename T, size_t ROWS, size_t COLS>
class Matrix {
public:
Matrix(const T & init = T()) : elts(ROWS, vector<T>(COLS, init)) {
}
const vector<T> & operator[](int r) const {
return elts[r];
} //not sure if correct
vector<T> & operator[](int r) {
return elts[r];
} //not sure if correct
//MatrixAdd
Matrix & matrixAdd(const Matrix & lhs, const Matrix & rhs) {
for (int r = 0; r < ROWS; r++) {
for (int c = 0; c < COLS; c++) {
this->elts[r][c] = lhs[r][c] + rhs[r][c];
}
}
return *this;
}
//MatrixSubtract
Matrix & matrixSubtract(const Matrix & lhs, const Matrix & rhs) {
for (int r = 0; r < ROWS; r++) {
for (int c = 0; c < COLS; c++) {
this->elts[r][c] = lhs[r][c] - rhs[r][c];
}
}
return *this;
}
//MatrixMult
template<size_t OUTER>
Matrix<T, ROWS, OUTER> matrixMult(const Matrix<T, COLS, OUTER> & mat2) const {
return innerProduct(*this , mat2);
} //not done
//print function
void print(ostream & out) const {
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
out << elts[i][j];
}
out << "\n";
}
}
private:
vector< vector<T> > elts;
};
//Note, you have to define each time a template to avoid having the errors
//Operator<<
template<class T, size_t ROWS, size_t INNER, size_t COLS>
static Matrix<T, ROWS, COLS> innerProduct(const Matrix<T, ROWS, INNER> & mat1, const Matrix<T, INNER, COLS> & mat2) {
Matrix<T, ROWS, COLS> result;
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
//elts[i][j] = 0;
for (int k = 0; k < INNER; k++) {
result.elts[i][j] += mat1.elts[i][k] * mat2.elts[k][j];
}
}
}
return result;
} //not done
template <typename T, size_t ROWS, size_t COLS>
ostream & operator<<(ostream & out, const Matrix<T, ROWS, COLS> & elts) {
elts.print(out);
return out;
}
//Operator==
template <typename T, size_t ROWS, size_t COLS>
bool operator==(const Matrix<T, ROWS, COLS> & lhs, const Matrix<T, ROWS, COLS> & rhs) {
return true;
}
//Operator+
template <typename T, size_t ROWS, size_t COLS>
Matrix<T, ROWS, COLS> operator+(const Matrix<T, ROWS, COLS> & lhs, const Matrix<T, ROWS, COLS> & rhs) {
Matrix<T, ROWS, COLS> returnVal;
return returnVal.matrixAdd(lhs, rhs);
}
//Operator-
template <typename T, size_t ROWS, size_t COLS>
Matrix<T, ROWS, COLS> operator-(const Matrix<T, ROWS, COLS> & lhs, const Matrix<T, ROWS, COLS> & rhs) {
Matrix<T, ROWS, COLS> returnVal;
return returnVal.matrixSubtract(lhs, rhs);
}
//Operator*
template <typename T, size_t ROWS, size_t COLS>
Matrix<T, ROWS, COLS> operator*(const Matrix<T, ROWS, COLS> & lhs, const Matrix<T, ROWS, COLS> & rhs) {
Matrix<T, ROWS, COLS> returnVal;
return returnVal.matrixMult(lhs, rhs);
}
//Operator+=
template <typename T, size_t ROWS, size_t COLS, typename C>
Matrix<T, ROWS, COLS> operator+=(Matrix<T, ROWS, COLS> & lhs, const C & rhs) {
//Matrix<T,ROWS,COLS> returnVal;
lhs.matrixAdd(lhs, rhs);
return lhs;
}
//Operator-=
template <typename T, size_t ROWS, size_t COLS, typename C>
Matrix<T, ROWS, COLS> operator-=(Matrix<T, ROWS, COLS> & lhs, const C & rhs) {
lhs.matrixSubtract(lhs, rhs);
return lhs;
}
//Operator*=
template <typename T, size_t ROWS, size_t COLS, typename C>
Matrix<T, ROWS, COLS> operator*=(Matrix<T, ROWS, COLS> & lhs, const C & rhs) {
lhs.matrixMult(lhs, rhs);
return lhs;
}
//Operator/=
template <typename T, size_t ROWS, size_t COLS>
Matrix<T, ROWS, COLS> operator/=(const Matrix<T, ROWS, COLS> & lhs, const int rhs) {
Matrix<T, ROWS, COLS> returnVal(rhs);
for (int r = 0; r < ROWS; r++) {
for (int c = 0; c < COLS; c++) {
returnVal[r][c] = lhs[r][c] / returnVal[r][c];
}
}
return returnVal;
}
//Operator%=
template <typename T, size_t ROWS, size_t COLS>
Matrix<T, ROWS, COLS> operator%=(const Matrix<T, ROWS, COLS> & lhs, const int rhs) {
Matrix<T, ROWS, COLS> returnVal(rhs);
for (int r = 0; r < ROWS; r++) {
for (int c = 0; c < COLS; c++) {
returnVal[r][c] = lhs[r][c] % returnVal[r][c];
}
}
return returnVal;
}
}

Related

Scalar multiplication of template class not working

This error is occurring when I am doing scalar multiplication. I am using template classes to perform these operations on matrices.
I have been trying to grasp at the concepts, but I seem to be failing. Any help is appreciated.
main.cpp inside main function
Matrix<int, 3, 3> m4;
Matrix<int, 3, 3> m5(3);
m5 = m4 * 2; //This works
m5 = 2 * m4; //Gives an error for this
cout << m5 << endl;
matrix.h
#include <exception>
template <class T, int M, int N>
Matrix<T, M, N> operator*(T, const Matrix<T, M, N> &);
template <class T, int M, int N>
class Matrix
{
private:
T mat[M][N];
int rows = M;
int cols = N;
public:
// Error class
class IllegalOperation : public std::exception
{
public:
IllegalOperation(const char *msg) : _msg(msg) {}
virtual const char *what() const throw() { return _msg.c_str(); };
private:
std::string _msg;
};
// constructor
Matrix(int v = 0)
{
for (int i = 0; i < M; i++)
{
for (int j = 0; j < N; j++)
mat[i][j] = v;
}
}
// () overloading
T &operator()(int i, int j)
{
return mat[i][j];
}
const T &operator()(int i, int j) const
{
return mat[i][j];
}
// [] overloading
T *operator[](int index)
{
return mat[index];
}
const T *operator[](int index) const
{
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, N1> operator*(Matrix<T1, M1, N1> const &other);
template <class T1, int M1, int N1>
const Matrix<T, M, N1> operator*(Matrix<T1, M1, N1> const &other) const;
Matrix<T, M, N> operator+(Matrix<T, M, N> const &other);
// scalar
Matrix<T, M, N> operator*(T);
friend Matrix<T, M, N> operator*<>(T scalar, const Matrix<T, M, N> &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, N> 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 IllegalOperation("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, N1> Matrix<T, M, N>::operator*(Matrix<T1, M1, N1> const &other)
{
std::cout << M << " " << N1;
if (N == M1)
{
Matrix<T, M, N1> 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 IllegalOperation("Matrices cannot be multipled, sizes not compatible");
}
template <class T, int M, int N>
template <class T1, int M1, int N1>
Matrix<T, M, N1> const Matrix<T, M, N>::operator*(Matrix<T1, M1, N1> const &other) const
{
if (N == M1)
{
Matrix<T, M, N1> 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 IllegalOperation("Matrices cannot be multipled, sizes not compatible");
}
Function for m * 2, and this works
// scalar m * T
template <class T, int M, int N>
Matrix<T, M, N> Matrix<T, M, N>::operator*(T scalar)
{
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];
if (scalar == 0)
resultantMatrix(i, j) = 0;
// else if ((multiplicationOverflow(valueFirst, scalar)) || (multiplicationUnderflow(valueFirst, scalar)))
// throw std::out_of_range("Resultant value of matrix is out of range");
else
resultantMatrix(i, j) = this->mat[i][j] * scalar;
}
}
return resultantMatrix;
}
Function for 2 * m, this does not work
template <class T, int M, int N>
Matrix<T, M, N> operator*(T scalar, const Matrix<T, M, N> &other)
{
Matrix<T, M, N> resultantMatrix;
for (auto i = 0; i < M; i++)
{
for (auto j = 0; j < N; j++)
{
auto valueFirst = other(i, j);
if (scalar == 0)
resultantMatrix(i, j) = 0;
// else if ((multiplicationOverflow(valueFirst, scalar)) || (multiplicationUnderflow(valueFirst, scalar)))
// throw std::out_of_range("Resultant value of matrix is out of range");
else
resultantMatrix(i, j) = other(i, j) * scalar;
}
}
return resultantMatrix;
}
Errors
In file included from main.cpp:3:
matrix.h:4:1: error: ‘Matrix’ does not name a type
4 | Matrix<T, M, N> operator*(T, const Matrix<T, M, N> &);
| ^~~~~~
matrix.h: In instantiation of ‘class Matrix<int, 3, 2>’:
main.cpp:10:29: required from here
matrix.h:76:28: error: template-id ‘operator*<>’ for ‘Matrix<int, 3, 2> operator*(int, const Matrix<int, 3, 2>&)’ does not match any template declaration
76 | friend Matrix<T, M, N> operator*<>(T scalar, const Matrix<T, M, N> &other);
| ^~~~~~~~~~~
matrix.h:210:17: note: candidates are: ‘Matrix<T, M, N> Matrix<T, M, N>::operator*(T)’
210 | Matrix<T, M, N> Matrix<T, M, N>::operator*(T scalar)
| ^~~~~~~~~~~~~~~
matrix.h:71:28: note: ‘template<class T, int M, int N> template<class T1, int M1, int N1> const Matrix<T, M, N1> Matrix<T, M, N>::operator*(const Matrix<T1, M1, N1>&) const’
71 | const Matrix<T, M, N1> operator*(Matrix<T1, M1, N1> const &other) const;
| ^~~~~~~~
matrix.h:69:22: note: ‘template<class T, int M, int N> template<class T1, int M1, int N1> Matrix<T, M, N1> Matrix<T, M, N>::operator*(const Matrix<T1, M1, N1>&)’
69 | Matrix<T, M, N1> operator*(Matrix<T1, M1, N1> const &other);
| ^~~~~~~~
matrix.h: In instantiation of ‘class Matrix<int, 3, 3>’:
main.cpp:12:25: required from here
matrix.h:76:28: error: template-id ‘operator*<>’ for ‘Matrix<int, 3, 3> operator*(int, const Matrix<int, 3, 3>&)’ does not match any template declaration
76 | friend Matrix<T, M, N> operator*<>(T scalar, const Matrix<T, M, N> &other);
| ^~~~~~~~~~~
matrix.h:210:17: note: candidates are: ‘Matrix<T, M, N> Matrix<T, M, N>::operator*(T)’
210 | Matrix<T, M, N> Matrix<T, M, N>::operator*(T scalar)
| ^~~~~~~~~~~~~~~
matrix.h:71:28: note: ‘template<class T, int M, int N> template<class T1, int M1, int N1> const Matrix<T, M, N1> Matrix<T, M, N>::operator*(const Matrix<T1, M1, N1>&) const’
71 | const Matrix<T, M, N1> operator*(Matrix<T1, M1, N1> const &other) const;
| ^~~~~~~~
matrix.h:69:22: note: ‘template<class T, int M, int N> template<class T1, int M1, int N1> Matrix<T, M, N1> Matrix<T, M, N>::operator*(const Matrix<T1, M1, N1>&)’
69 | Matrix<T, M, N1> operator*(Matrix<T1, M1, N1> const &other);
You need to forward declare your class before you use it, like this.
template <class T, int M, int N>
class Matrix;
template <class T, int M, int N>
Matrix<T, M, N> operator*(T, const Matrix<T, M, N> &);
template <class T, int M, int N>
class Matrix
{
...
};
A simpler option would be to remove the declaration of operator* and just define it after the definition of Matrix. Like this
template <class T, int M, int N>
class Matrix
{
...
};
template <class T, int M, int N>
Matrix<T, M, N> operator*(T, const Matrix<T, M, N> &)
{
...
}
but maybe that will cause problems elsewhere in your code, I can't see enough of it to tell.

template argument deduction for a allocating Matrix

I have this Matrix class that allocates the data on the heap and a helper class M that is a Matrix with the data as C-style array, no allocation. Template argument deduction works for the helper class automatically. But not for the Matrix class.
I can construct a Matrix from that with template argument deduction:
M m{{{1, 2}, {3, 4}}};
Matrix a{M{{{1, 2}, {3, 4}}}};
What I'm looking for is to get rid of the helper class so the following works:
Matrix a{{{1, 2}, {3, 4}}};
Here is a working example with the helper class: https://godbolt.org/z/46vEqbvax
#include <cstddef>
#include <type_traits>
#include <cstring>
#include <initializer_list>
#include <utility>
#include <memory>
#include <cassert>
#include <algorithm>
template <typename T, std::size_t rows, std::size_t cols>
class M {
public:
const T * operator[](std::size_t x) const {
return data[x];
}
T * operator[](std::size_t x) {
return data[x];
}
T data[rows][cols]{};
};
template <typename T, std::size_t rows, std::size_t cols>
class Matrix {
private:
T *data{new T[rows * cols]};
public:
Matrix() { }
~Matrix() {
delete[] data;
data = nullptr; // crash on use after free
}
Matrix(const Matrix &other) {
*this = other;
}
Matrix(T &&other) : data(other.data) {
other.data = nullptr;
}
Matrix & operator=(const Matrix &other) {
if constexpr (std::is_aggregate_v<T>) {
memcpy(data, other.data, sizeof(T) * rows * cols);
} else {
for (std::size_t i = 0; i < rows; ++i) {
for (std::size_t j = 0; j < cols; ++j) {
(*this)[i][j] = other[i][j];
}
}
}
return *this;
}
Matrix operator=(Matrix &&other) {
swap(data, other.data);
return *this;
}
const T * operator[](std::size_t x) const {
return &data[x * cols];
}
T * operator[](std::size_t x) {
return &data[x * cols];
}
Matrix(const M<T, rows, cols>& other) {
if constexpr (std::is_aggregate_v<T>) {
memcpy(data, other.data, sizeof(T) * rows * cols);
} else {
for (std::size_t i = 0; i < rows; ++i) {
for (std::size_t j = 0; j < cols; ++j) {
(*this)[i][j] = other[i][j];
}
}
}
}
Matrix(M<T, rows, cols>&& other) {
if constexpr (std::is_aggregate_v<T>) {
memcpy(data, other.data, sizeof(T) * rows * cols);
} else {
for (std::size_t i = 0; i < rows; ++i) {
for (std::size_t j = 0; j < cols; ++j) {
std::swap((*this)[i][j], other[i][j]);
}
}
}
}
};
//template <typename T, std::size_t rows, std::size_t cols>
//Matrix(M<T, rows, cols>) -> Matrix<T, rows, cols>;
#include <iostream>
int main() {
Matrix a{M{{{1, 2}, {3, 4}}}};
Matrix b{a};
std::cout << b[0][0] << " " << b[0][1] << std::endl;
std::cout << b[1][0] << " " << b[1][1] << std::endl;
}
You can get rid of helper class M and have your Matrix template parameters automatically deduced by changing the type of your constructor parameters to (l- and r-value references to) C-style arrays:
//Matrix(const M<T, rows, cols>& other) {
Matrix(const T (&other)[rows][cols]) {
// ... same implementation ...
}
//Matrix(M<T, rows, cols>&& other) {
Matrix(T (&&other)[rows][cols]) {
// ... same implementation ...
}
Demo

multiplying matrices of variable sizes

I have built a class that declares a m, n matrix with elements of different types.
template<typename T>
class Matrix {
public:
int m, n;
T *elements;
How would I now go about overloading an operator to multiply two matrices?
I am mostly confused about dealing with matrices that can take on a variety of sizes.
I know that I will need this line but I am not sure what to do after:
Matrix<T> operator*(Matrix<T> const &b)
The following code is untested, but it should give you an idea of how to do matrix multiplication.
I would suggest defining the operator* as a free function rather than a member function.
template<typename T>
class Matrix
{
public:
Matrix(int r, int c)
: rows(r)
, cols(c)
, elements.resize(rows * cols)
{ }
int rows = 0, cols = 0;
T& operator()(int i, int j) { return elements[i * ncols + j]; }
std::vector<T> elements;
};
template<typename T>
Matrix<T> operator*(Matrix<T> const& a, Matrix<T> const& b)
{
assert(a.cols == b.rows);
Matrix<T> c(a.rows, b.cols);
for (int output_row = 0; output_row < a.rows; ++output_row)
{
for (int output_col = 0; output_col < b.cols; ++output_col)
{
double sum = 0.0;
for (int i = 0; i < a.cols; ++i)
sum += a(output_row, i) * b(i, output_col);
c(output_row, output_col) = sum;
}
}
return c;
}

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, i.e. 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");
}

Can't get template classes to work well with the linker

I'm currently teaching myself C++, and I'm struggling to get my implementation of a basic template class to compile. I wrote a IntMatrix class that implements a matrix with integer elements, and I'm now trying to extend the class. Code is below. When I try to compile it, I get the error:
g++ -o hw3 -std=c++11 -Wall -Wextra -ansi -pedantic -Wshadow -Weffc++ -Wstrict-overflow=5 -Wno-unused-parameter -Wno-write-strings hw3.cpp
Undefined symbols for architecture x86_64:
"Matrix<int>::~Matrix()", referenced from:
_main in hw3-c5e16c.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I would be extremely grateful for any assistance. Code:
// main.cpp
#include "matrix.ch"
#include <iostream>
int main() {
Matrix<int> adj(3, 3);
std::cout << adj;
return 0;
}
The matrix header file:
// matrix.h
#ifndef MATRIX_H
#define MATRIX_H
#include <iostream>
#include <iomanip>
using namespace std;
template <typename T>
class Matrix {
public:
//Default constructor.
Matrix( );
//Constructor builds r x c matrix with all zeros.
Matrix(int r, int c);
//Class destructor.
~Matrix( );
//Copy constructor.
Matrix(const Matrix<T>& right);
void print( );
//Assignment operator.
Matrix<T>& operator= (const Matrix<T>& right);
//Element access operator: M(i,j) is element in row i, column j.
int& operator() (int i, int j);
int operator() (int i, int j) const;
//Define matrix addition: A+B.
//Assumes dimension(A)=dimension(B).
friend Matrix<T> operator+ (const Matrix<T>& left, const Matrix<T>& right);
//Define matrix multiplication: A*B.
//Assumes (#cols of A) = (#rows of B).
friend Matrix<T> operator* (const Matrix<T>& left, const Matrix<T>& right);
//Define matrix powers: A^N = A*A*A...A (N times).
//Assumes matrix A is square: #rows = #cols.
friend Matrix<T> operator^<>(const Matrix<T>& left, int power);
//Define matrix input and output.
friend ostream& operator<< (ostream& out, const Matrix<T>& right);
friend istream& operator>> (istream& in, Matrix<T>& right);
private:
int rows; //Number of rows in matrix.
int cols; //Number of columns in matrix.
T* elements; //Matrix elements as an array, read in raster order.
};
template <typename T>
Matrix<T>::Matrix() {
rows = 0;
cols = 0;
elements = NULL;
}
template <typename T>
Matrix<T>::Matrix (int r, int c) {
rows = r;
cols = c;
elements = new T[r*c];
}
template <typename T>
Matrix<T>::~Matrix () {
delete[] elements;
}
template <typename T>
void Matrix<T>::print() {
for (int i = 0; i < rows * cols; i++) {
cout <<setw(10) << elements[i];
if ((i+1) % cols == 0) {
cout << "\n"; // End of row
}
return;
}
}
template <typename T>
int& Matrix<T>::operator() (int i, int j) {
return elements[i * cols + j];
}
template <typename T>
int Matrix<T>::operator() (int i, int j) const{
return elements[i * cols + j];
}
template <typename T>
ostream& operator<< (ostream& out, const Matrix<T>& right) {
for (int i = 0; i < right.rows*right.cols; i++) {
out << setw(10) << right.elements[i];
if ((i+1) % right.cols == 0) {
out << "\n";
}
}
return out;
}
template <typename T>
Matrix<T> operator* (const Matrix<T>& left, const Matrix<T>& right) {
Matrix<T> A (left.rows, right.cols);
for (int i = 0; i < left.rows; i++) {
for (int j = 0; j < right.cols; j++) {
A(i, j) = 0;
for (int k = 0; k < left.cols; k++) {
A(i, j) += left(i, k) * right (k, j);
}
}
}
return A;
}
template <typename T>
Matrix<T>& Matrix<T>::operator= (const Matrix<T>& right) {
if (this != &right) {
rows = right.rows;
cols = right.cols;
delete[] elements; // Note that we clear the array before reassigning it.
elements = new T[rows * cols];
for (int i = 0; i < rows * cols; i++) {
elements[i] = right.elements[i];
}
}
return *this;
}