Hi guys,
I am writing a matrix class - and wanted to get some feedback. My idea is that one should be capable of creating both fixed-size(compile-time) and dynamic matrices. So, containerType
template parameter would be either std::array<T,N>
or std::vector<N>
.
I should provide proper iterators to traverse through my matrix and also need to overload the assignment operator.
[CODE lang="cpp" title="Matrix.h"]#pragma once
#include <array>
#include <vector>
template <typename T, int r, int c, typename cType=std::array<T,r*c>>
class Matrix;
using Matrix1d = Matrix<double, 1, 1>;
using Matrix2d = Matrix<double, 2, 2>;
using Matrix3d = Matrix<double, 3, 3>;
using Matrix4d = Matrix<double, 4, 4>;
using Matrix1i = Matrix<int, 1, 1>;
using Matrix2i = Matrix<int, 2, 2>;
using Matrix3i = Matrix<int, 3, 3>;
using Matrix4i = Matrix<int, 4, 4>;
using Matrix1f = Matrix<float, 1, 1>;
using Matrix2f = Matrix<float, 2, 2>;
using Matrix3f = Matrix<float, 3, 3>;
using Matrix4f = Matrix<float, 4, 4>;
using Vector1d = Matrix<double, 1, 1>;
using Vector2d = Matrix<double, 1, 2>;
using Vector3d = Matrix<double, 1, 3>;
using Vector4d = Matrix<double, 1, 4>;
using Vector1i = Matrix<int, 1, 1>;
using Vector2i = Matrix<int, 2, 2>;
using Vector3i = Matrix<int, 3, 3>;
using Vector4i = Matrix<int, 4, 4>;
using Vector1f = Matrix<float, 1, 1>;
using Vector2f = Matrix<float, 2, 2>;
using Vector3f = Matrix<float, 3, 3>;
using Vector4f = Matrix<float, 4, 4>;
using MatrixXi = Matrix<int, 0, 0, std::vector<int>>;
using MatrixXd = Matrix<double, 0, 0, std::vector<double>>;
using MatrixXf = Matrix<float, 0, 0, std::vector<float>>;
template <typename scalarType, int rowsAtCompileTime = 0, int colsAtCompileTime = 0, typename containerType = std::array<scalarType,(rowsAtCompileTime * colsAtCompileTime)>>
class Matrix
{
private:
containerType A;
int _rows;
int _cols;
public:
Matrix() = default;
Matrix(const Matrix& m);
int rows() const;
int cols() const;
int size() const;
//Overloaded operators
scalarType operator()(const int i, const int j) const;
scalarType& operator()(const int i, const int j);
Matrix operator+(const Matrix& m) const;
Matrix operator-(const Matrix& m) const;
Matrix operator*(const Matrix& m) const;
};[/CODE]
[CODE lang="cpp" title="Matrix.cpp"]
#pragma once
#include "Matrix.h"
#include <stdexcept>
template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime, typename containerType>
Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType>::Matrix(const Matrix& m):A{m.A}, _rows{m.rows()}, _cols{m.cols()}, _size{m.size()}
{
}
template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime, typename containerType>
int Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType>::rows() const
{
return _rows;
}
template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime, typename containerType>
int Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType>::cols() const
{
return _cols;
}
template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime, typename containerType>
int Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType>::size() const
{
return A.size();
}
/// <summary>
/// Coefficient accessors.
/// The primary coefficient accessor is the overloaded parenthesis operators. The data of the matrix
/// is stored in an underlying sequential container such as std::array or std::vector. The element
/// A(i,j) is at an offset of (i*_cols)+j in memory.
/// </summary>
/// <typeparam name="scalarType"></typeparam>
/// <typeparam name="containerType"></typeparam>
/// <param name="i">The row index</param>
/// <param name="j">The col index</param>
/// <returns>The element at position (i,j)</returns>
template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime, typename containerType>
scalarType Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType>::operator()(const int i, const int j) const
{
containerType::const_iterator it{ A.begin() };
it = it + (i * _cols) + j;
if (it < A.end())
return *it;
else
throw std::out_of_range("\nError accessing an element beyond matrix bounds");
}
/// <summary>
/// Matrix addition.
/// Overload of the binary operator +. The left hand side and the right hand side matrix must have
/// the same number of rows and columns.
/// </summary>
/// <typeparam name="scalarType"></typeparam>
/// <typeparam name="containerType"></typeparam>
/// <param name="i"></param>
/// <param name="j"></param>
/// <returns></returns>
template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime, typename containerType>
scalarType& Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType>::operator()(const int i, const int j)
{
containerType::iterator it{ A.begin() };
it = it + (i * _cols) + j;
if (it < A.end())
return *it;
else
throw std::out_of_range("\nError accessing an element beyond matrix bounds");
}
template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime, typename containerType>
Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType> Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType>::operator+(const Matrix& m) const
{
Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType> result{};
if (this->rows() == m.rows() && this->cols() == m.cols())
{
containerType::const_iterator it1{ A.begin() };
containerType::const_iterator it2{ m.A.begin() };
containerType::iterator resultIter{ result.A.begin() };
while (it1 < A.end() && it2 < m.A.end())
{
*resultIter = *it1 + *it2;
++it1; ++it2; ++resultIter;
}
}
else
{
throw std::logic_error("Matrices have different dimensions; therefore cannot be added!");
}
return result;
}
template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime, typename containerType>
Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType> Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType>::operator-(const Matrix& B) const
{
Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType> result{};
if (this->rows() == m.rows() && this->cols() == m.cols())
{
containerType::const_iterator it1{ A.begin() };
containerType::const_iterator it2{ m.A.begin() };
containerType::iterator resultIter{ result.A.begin() };
while (it1 < A.end() && it2 < m.A.end())
{
*resultIter = *it1 - *it2;
++it1; ++it2; ++resultIter;
}
}
else
{
throw std::logic_error("Matrices have different dimensions; therefore cannot be added!");
}
return result;
}
template<typename scalarType, int m, int n, int p, typename containerType>
Matrix<scalarType, m, p, containerType> operator*(const Matrix<scalarType, m, n, containerType>& A, const Matrix<scalarType, n, p, containerType>& B)
{
Matrix<scalarType, m, p, containerType> result;
for (int i{}; i < m; ++i)
{
for (int k{}; k < p; ++k)
{
scalarType sum{};
for (int j{}; j < n; ++j)
{
sum += A(i, j) * B(j, k);
}
result(i, k) = sum;
}
}
}
[/CODE]
Sorry for the duplication, but posting some working code now. One failure I corrected:
- When using class templates, the member function definitions should have been in the same header-file Matrix.h, because these are really function templates (not instantiated). Failing to do this results in the compiler not instantiating them, and the linker would complain about missing symbols.
A matrix M can be initialized as, M << 1, 0, 0,
0, 1, 0,
0, 0, 1.
Nice to have functionality.
Any suggestions/feedback is super-helpful.
[CODE lang="cpp" title="Matrix.h"]
#pragma once
#include <array>
#include <vector>
#include <stdexcept>
#include <type_traits>
#include <iterator>
template <typename T, int r=0, int c=0, typename cType=std::array<T,r*c>>
class Matrix;
using Matrix1d = Matrix<double, 1, 1, std::array<double,1>>;
using Matrix2d = Matrix<double, 2, 2, std::array<double, 4>>;
using Matrix3d = Matrix<double, 3, 3, std::array<double, 9>>;
using Matrix4d = Matrix<double, 4, 4, std::array<double, 16>>;
using Matrix1i = Matrix<int, 1, 1, std::array<int, 1>>;
using Matrix2i = Matrix<int, 2, 2, std::array<int, 4>>;
using Matrix3i = Matrix<int, 3, 3, std::array<int, 9>>;
using Matrix4i = Matrix<int, 4, 4, std::array<int, 16>>;
using Matrix1f = Matrix<float, 1, 1, std::array<float, 1>>;
using Matrix2f = Matrix<float, 2, 2, std::array<float, 4>>;
using Matrix3f = Matrix<float, 3, 3, std::array<float, 9>>;
using Matrix4f = Matrix<float, 4, 4, std::array<float, 16>>;
using Vector1d = Matrix<double, 1, 1, std::vector<double>>;
using Vector2d = Matrix<double, 1, 2, std::vector<double>>;
using Vector3d = Matrix<double, 1, 3, std::vector<double>>;
using Vector4d = Matrix<double, 1, 4, std::vector<double>>;
using Vector1i = Matrix<int, 1, 1, std::vector<double>>;
using Vector2i = Matrix<int, 2, 2, std::vector<double>>;
using Vector3i = Matrix<int, 3, 3, std::vector<double>>;
using Vector4i = Matrix<int, 4, 4, std::vector<double>>;
using Vector1f = Matrix<float, 1, 1, std::vector<double>>;
using Vector2f = Matrix<float, 2, 2, std::vector<double>>;
using Vector3f = Matrix<float, 3, 3, std::vector<double>>;
using Vector4f = Matrix<float, 4, 4, std::vector<double>>;
using MatrixXi = Matrix<int, 0, 0, std::vector<int>>;
using MatrixXd = Matrix<double, 0, 0, std::vector<double>>;
using MatrixXf = Matrix<float, 0, 0, std::vector<float>>;
template <typename scalarType, int rowsAtCompileTime, int colsAtCompileTime>
class Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>>
{
private:
std::array<scalarType, rowsAtCompileTime* colsAtCompileTime> A;
int _rows;
int _cols;
int _size;
typename std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>::iterator currentPosition{A.begin()};
public:
Matrix();
Matrix(int m, int n);
Matrix(const Matrix& m);
int rows() const;
int cols() const;
int size() const;
//Overloaded operators
scalarType operator()(const int i, const int j) const; //Subscript operator
scalarType& operator()(const int i, const int j); //Subscript operator const arrays
Matrix operator+(const Matrix& m) const;
Matrix operator-(const Matrix& m) const;
Matrix& operator<<(const scalarType x);
Matrix& operator,(const scalarType x);
Matrix& operator=(const Matrix& right_hand_side);
};
template <typename scalarType>
class Matrix<typename scalarType, 0, 0, std::vector<scalarType>>
{
private:
std::vector<scalarType> A;
int _rows;
int _cols;
int _size;
typename std::vector<scalarType>::iterator currentPosition{};
public:
Matrix();
Matrix(int m, int n);
Matrix(const Matrix& m);
int rows() const;
int cols() const;
int size() const;
//Overloaded operators
scalarType operator()(const int i, const int j) const;
scalarType& operator()(const int i, const int j);
Matrix operator+(const Matrix& m) const;
Matrix operator-(const Matrix& m) const;
Matrix& operator<<(const scalarType x);
Matrix& operator,(const scalarType x);
Matrix& operator=(const Matrix& right_hand_side);
};
// Non-member operator functions
template<typename scalarType, int m, int n, int p, int q>
Matrix<scalarType, m, q, std::vector<scalarType>> operator*(const Matrix<scalarType, m, n, std::vector<scalarType>>& A, const Matrix<scalarType, p, q, std::vector<scalarType>>& B);
template<typename scalarType, int m, int n, int p, int q>
Matrix<scalarType, m, q, std::array<scalarType,m*q>> operator*(const Matrix<scalarType, m, n, std::array<scalarType,m*n>>& A, const Matrix<scalarType, p, q, std::array<scalarType,p*q>>& B);
//Default constructor
template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime>
inline Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>>::Matrix():_rows{rowsAtCompileTime}, _cols{colsAtCompileTime}, currentPosition{A.begin()}
{
//Do nothing.
}
//Default constructor
template<typename scalarType>
inline Matrix<typename scalarType, 0, 0, std::vector<scalarType>>::Matrix() :_rows{ 0 }, _cols{ 0 }
{
currentPosition = A.begin();
}
//Fixed-Size matrices
template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime>
inline Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType,rowsAtCompileTime * colsAtCompileTime>>::Matrix(int m, int n)
{
//Do nothing.
}
//Run-time matrices
template<typename scalarType>
inline Matrix<typename scalarType, 0, 0, std::vector<scalarType>>::Matrix(int m, int n) : currentPosition{A.begin()}
{
int numOfElements{ m * n };
for (int i{}; i < numOfElements; ++i)
{
A.push_back(0);
}
}
template<typename scalarType>
inline Matrix<typename scalarType, 0, 0, std::vector<scalarType>>::Matrix(const Matrix& m): A{m.A}, _rows{m.rows()}, _cols{m.cols()}, currentPosition{m.currentPosition}
{
}
template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime>
inline Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType,rowsAtCompileTime*colsAtCompileTime>>::Matrix(const Matrix& m) : A{ m.A }, _rows{ m.rows() }, _cols{ m.cols() }, currentPosition{ m.currentPosition }
{
}
template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime>
inline int Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType,rowsAtCompileTime* colsAtCompileTime>>::rows() const
{
return _rows;
}
template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime>
inline int Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>>::cols() const
{
return _cols;
}
template<typename scalarType>
inline int Matrix<scalarType, 0, 0, std::vector<scalarType>>::rows() const
{
return _rows;
}
template<typename scalarType>
inline int Matrix<scalarType, 0, 0, std::vector<scalarType>>::cols() const
{
return _cols;
}
template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime>
inline int Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>>::size() const
{
return A.size();
}
template<typename scalarType>
inline int Matrix<scalarType, 0, 0, std::vector<scalarType>>::size() const
{
return A.size();
}
template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime>
inline scalarType Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>>::operator()(const int i, const int j) const
{
typename std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>::const_iterator it{ A.begin() };
it = it + (i * _cols) + j;
if (it < A.end())
return *it;
else
throw std::out_of_range("\nError accessing an element beyond matrix bounds");
}
template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime>
inline scalarType& Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>>::operator()(const int i, const int j)
{
typename std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>::iterator it{ A.begin() };
it = it + (i * _cols) + j;
if (it < A.end())
return *it;
else
throw std::out_of_range("\nError accessing an element beyond matrix bounds");
}
template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime>
inline Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>> Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>>::operator+(const Matrix& m) const
{
Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>> result{};
if (this->rows() == m.rows() && this->cols() == m.cols())
{
typename std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>::const_iterator it1{ A.begin() };
typename std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>::const_iterator it2{ m.A.begin() };
typename std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>::iterator resultIter{ result.A.begin() };
while (it1 < A.end() && it2 < m.A.end())
{
*resultIter = *it1 + *it2;
++it1; ++it2; ++resultIter;
}
}
else
{
throw std::logic_error("Matrices have different dimensions; therefore cannot be added!");
}
return result;
}
template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime>
inline Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>> Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>>::operator-(const Matrix& m) const
{
Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>> result{};
if (this->rows() == m.rows() && this->cols() == m.cols())
{
typename std::array<scalarType, rowsAtCompileTime*colsAtCompileTime>::const_iterator it1{ A.begin() };
typename std::array<scalarType, rowsAtCompileTime*colsAtCompileTime>::const_iterator it2{ m.A.begin() };
typename std::array<scalarType, rowsAtCompileTime*colsAtCompileTime>::iterator resultIter{ result.A.begin() };
while (it1 < A.end() && it2 < m.A.end())
{
*resultIter = *it1 - *it2;
++it1; ++it2; ++resultIter;
}
}
else
{
throw std::logic_error("Matrices have different dimensions; therefore cannot be added!");
}
return result;
}
template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime>
inline Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>>& Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>>::operator<<(const scalarType x)
{
if (currentPosition < A.end())
{
*currentPosition = x;
++currentPosition;
}
else
{
throw std::logic_error("Error: Attempting to set values beyond matrix bounds!");
}
return *this;
}
template<typename scalarType>
inline Matrix<typename scalarType, 0, 0, std::vector<scalarType>>& Matrix<typename scalarType, 0, 0, std::vector<scalarType>>::operator<<(const scalarType x)
{
if (currentPosition < A.end())
{
*currentPosition = x;
++currentPosition;
}
else
{
throw std::logic_error("Error: Attempting to set values beyond matrix bounds!");
}
return *this;
}
template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime>
inline Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>>& Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>>::operator,(const scalarType x)
{
if (currentPosition < A.end())
{
*currentPosition = x;
++currentPosition;
}
else
{
throw std::logic_error("Error: Attempting to set values beyond matrix bounds!");
}
return *this;
}
template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime>
inline Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>>& Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>>::operator=(const Matrix& right_hand_side)
{
if (this == &right_hand_side)
return *this;
this->A = right_hand_side.A;
this->_rows = right_hand_side._rows;
this->_cols = right_hand_side._cols;
this->currentPosition = right_hand_side.currentPosition;
return *this;
}
template<typename scalarType>
inline Matrix<typename scalarType, 0, 0, std::vector<scalarType>>& Matrix<typename scalarType, 0, 0, std::vector<scalarType>>::operator=(const Matrix& right_hand_side)
{
if (this == &right_hand_side)
return *this;
this->A = right_hand_side.A;
this->_rows = right_hand_side._rows;
this->_cols = right_hand_side._cols;
this->currentPosition = right_hand_side.currentPosition;
return *this;
}
template<typename scalarType>
inline Matrix<typename scalarType, 0, 0, std::vector<scalarType>>& Matrix<typename scalarType, 0, 0, std::vector<scalarType>>::operator,(const scalarType x)
{
if (currentPosition < A.end())
{
*currentPosition = x;
++currentPosition;
}
else
{
throw std::logic_error("Error: Attempting to set values beyond matrix bounds!");
}
return *this;
}
template<typename scalarType>
inline Matrix<typename scalarType, 0, 0, std::vector<scalarType>> Matrix<typename scalarType, 0, 0, std::vector<scalarType>>::operator+(const Matrix& m) const
{
Matrix<scalarType, 0, 0, std::vector<scalarType>> result{};
if (this->rows() == m.rows() && this->cols() == m.cols())
{
typename std::vector<scalarType>::const_iterator it1{ A.begin() };
typename std::vector<scalarType>::const_iterator it2{ m.A.begin() };
typename std::vector<scalarType>::iterator resultIter{ result.A.begin() };
while (it1 < A.end() && it2 < m.A.end())
{
*resultIter = *it1 - *it2;
++it1; ++it2; ++resultIter;
}
}
else
{
throw std::logic_error("Matrices have different dimensions; therefore cannot be added!");
}
return result;
}
template<typename scalarType>
inline Matrix<typename scalarType, 0, 0, std::vector<scalarType>> Matrix<typename scalarType, 0, 0, std::vector<scalarType>>::operator-(const Matrix& m) const
{
Matrix<scalarType, 0, 0, std::vector<scalarType>> result{};
if (this->rows() == m.rows() && this->cols() == m.cols())
{
typename std::vector<scalarType>::const_iterator it1{ A.begin() };
typename std::vector<scalarType>::const_iterator it2{ m.A.begin() };
typename std::vector<scalarType>::iterator resultIter{ result.A.begin() };
while (it1 < A.end() && it2 < m.A.end())
{
*resultIter = *it1 + *it2;
++it1; ++it2; ++resultIter;
}
}
else
{
throw std::logic_error("Matrices have different dimensions; therefore cannot be added!");
}
return result;
}
template<typename scalarType, int m, int n, int p, int q>
inline Matrix<scalarType, m, q, std::vector<scalarType>> operator*(const Matrix<scalarType, m, n, std::vector<scalarType>>& A, const Matrix<scalarType, p, q, std::vector<scalarType>>& B)
{
if (n != p)
throw std::logic_error("Error multiplying the matrices; the number of cols(A) must equal the number of rows(B)!");
Matrix<scalarType, m, q, std::vector<scalarType>> result;
for (int i{}; i < m; ++i)
{
for (int k{}; k < p; ++k)
{
scalarType sum{};
for (int j{}; j < n; ++j)
{
sum += A(i, j) * B(j, k);
}
result(i, k) = sum;
}
}
return result;
}
template<typename scalarType, int m, int n, int p, int q>
Matrix<scalarType, m, q, std::array<scalarType, m* q>> operator*(const Matrix<scalarType, m, n, std::array<scalarType, m* n>>& A, const Matrix<scalarType, p, q, std::array<scalarType, p* q>>& B)
{
if (n != p)
throw std::logic_error("Error multiplying the matrices; the number of cols(A) must equal the number of rows(B)!");
Matrix<scalarType, m, q, std::array<scalarType, m * q>> result;
for (int i{}; i < m; ++i)
{
for (int k{}; k < p; ++k)
{
scalarType sum{};
for (int j{}; j < n; ++j)
{
sum += A(i, j) * B(j, k);
}
result(i, k) = sum;
}
}
return result;
}
[/CODE]
[CODE lang="cpp" title="TestMatrix.cpp"]
// MatrixImpl.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <iostream>
#include "Matrix.h"
#include <iomanip>
int main()
{
Matrix<int, 3, 3> m1;
m1 <<1, 0, 0,
0, 1, 0,
0, 0, 1;
Matrix<int, 3, 3> m2;
m2 << 2, 0, 0,
0, 1, 0,
0, 0, 3;
Matrix<int, 3, 3> m3 = m1 + m2;
for (int i{}; i < 3; ++i)
{
for (int j{}; j < 3; ++j)
{
std::cout << std::setw(5) << m3(i, j);
}
std::cout << std::endl;
}
return 0;
}
[/CODE]