Related
I have templated MxN matrix class
template<typename T, size_t M, size_t N>
class Matrix {
public:
Matrix() { vecs_ = new Vector<T, N>[M]; }
Matrix(std::initializer_list<std::initializer_list<T>> l);
Matrix(const Matrix& m);
~Matrix() { delete[] vecs_; }
Matrix& operator=(const Matrix& m);
Matrix& operator+=(const Matrix& m);
Matrix& operator-=(const Matrix& m);
Matrix& operator*=(T c);
Matrix& operator/=(T c);
Vector<T, N> operator[](int row) const;
Vector<T, N>& operator[](int row);
Vector<T, M> operator*(const Vector<T, N>& b) const;
template<size_t P> Matrix<T, M, P> operator*(const Matrix<T, N, P>& b) const;
Matrix<T, N, M> Transpose() const;
size_t Rows() const { return M; }
size_t Columns() const { return N; }
protected:
Vector<T, N>* vecs_;
};
template<typename T, size_t M, size_t N> Matrix<T, M, N> operator+(const Matrix<T, M, N>& m) { return m; }
template<typename T, size_t M, size_t N> Matrix<T, M, N> operator-(const Matrix<T, M, N>& m) { return Matrix<T, M, N>() - m; }
template<typename T, size_t M, size_t N> Matrix<T, M, N> operator+(const Matrix<T, M, N>& a, const Matrix<T, M, N>& b) { return a += b; }
template<typename T, size_t M, size_t N> Matrix<T, M, N> operator-(const Matrix<T, M, N>& a, const Matrix<T, M, N>& b) { return a -= b; }
template<typename T, typename U, size_t M, size_t N> Matrix<T, M, N> operator*(Matrix<T, M, N> m, U c) { return m *= c; }
template<typename T, typename U, size_t M, size_t N> Matrix<T, M, N> operator*(U c, Matrix<T, M, N> m) { return m *= c; }
template<typename T, typename U, size_t M, size_t N> Matrix<T, M, N> operator/(Matrix<T, M, N> m, U c) { return m /= c; }
template<typename T, size_t M, size_t N>
std::ostream& operator<<(std::ostream& os, const Matrix<T, M, N>& m) { ... }
I wish to create NxN square matrix class that is derived from MxN matrix. This child class should inherit everything the parent have, including its operator overloads. This is what I tried
template<typename T, size_t N>
class SquareMatrix : public Matrix<T, N, N>
{
public:
using Matrix<T, N, N>::Matrix; // inherit all constructors from the base class
using Matrix<T, N, N>::operator=; // also inherit other operators
using Matrix<T, N, N>::operator+=;
using Matrix<T, N, N>::operator-=;
using Matrix<T, N, N>::operator*=;
using Matrix<T, N, N>::operator/=;
using Matrix<T, N, N>::operator*;
SquareMatrix(bool identity);
};
Is it a proper way to inherit? Are there any redundant lines? Is there anything else I need to add?
Also, I have problems with * and [] operator. In the parent matrix class, I have two overloads for each of these operators, each takes different parameter. Is there any way to distinguish between these two in the child square matrix class? using Matrix<T, N, N>::operator*; is bit ambiguous to compile.
I imagine all your functions work with matrices of arbitary sizes right? If i manually declare 2 square matricies:
Matrix<int, 5, 5> m1, m2;
Do operations work on them? If so, then you don't need inheritance, you just need to make it easy for the user to make this specific version of the matrix type, which you can achieve with a type alias:
template<typename T, size_t N>
using SquareMatrix = Matrix<T, N, N>;
And everything should just work.
If you want to add functions that are specific to the square matrix, aim to make them free functions:
template <typename T, size_t N>
constexpr SquareMatrix<T, N> identity() noexcept {
...
}
This gives you a nice abstraction and is very modern c++ style. AKA, a matrix could easily be set as follows:
auto m = matrix::identity<int, 5>();
I'm writing a simple matrix class that uses a template to define the datatype, as well as the number of rows and columns. However, I'm running into some issues when defining operator overloads. Here is the class so far:
template<typename T, size_t num_rows, size_t num_cols>
class Matrix {
public:
Matrix();
Matrix(const Matrix &m); // Copy constructor
~Matrix();
T operator()(const size_t row, const size_t col) const;
T& operator()(const size_t row, const size_t col);
Matrix& operator=(const Matrix &m); // Copy assignment operator
Matrix operator*(const Matrix &m2) const;
private:
T data_[num_rows][num_cols];
size_t num_rows_;
size_t num_cols_;
};
template<typename T, size_t num_rows, size_t num_cols>
Matrix<T, num_rows, num_cols>::Matrix() : num_rows_(num_rows), num_cols_(num_cols) {}
template<typename T, size_t num_rows, size_t num_cols>
Matrix<T, num_rows, num_cols>::~Matrix() {}
// Copy constructor
template<typename T, size_t num_rows, size_t num_cols>
Matrix<T, num_rows, num_cols>::Matrix(const Matrix &m) :
num_rows_(m.num_rows_),
num_cols_(m.num_cols_)
{
for(size_t i = 0; i < this->num_rows_; ++i) {
for(size_t j = 0; j < this->num_cols_; ++j) {
(*this)(i,j) = m(i,j);
}
}
}
template<typename T, size_t num_rows, size_t num_cols>
T Matrix<T, num_rows, num_cols>::operator()(const size_t row, const size_t col) const {
return data_[row][col];
}
template<typename T, size_t num_rows, size_t num_cols>
T& Matrix<T, num_rows, num_cols>::operator()(const size_t row, const size_t col) {
return data_[row][col];
}
// Copy assignment operator
template<typename T, size_t num_rows, size_t num_cols>
Matrix<T, num_rows, num_cols>& Matrix<T, num_rows, num_cols>::operator=(const Matrix &m) {
if(this == &m){
return *this;
}
for(size_t i = 0; i < this->num_rows_; ++i) {
for(size_t j = 0; j < this->num_cols_; ++j) {
(*this)(i,j) = m(i,j);
}
}
return *this;
}
// Multiplication operator overload
template<typename T, size_t num_rows, size_t num_cols>
Matrix<T, num_rows, num_cols> Matrix<T, num_rows, num_cols>::operator*(const Matrix &m2) const {
const size_t rows = this->num_rows_;
const size_t cols = m2.num_cols_;
Matrix<float, rows, cols> m3;
for(size_t i = 0; i < this->num_rows_; ++i) {
for(size_t j = 0; j < m2.num_cols_; ++j) {
m3(i,j) = 0.0f;
for(size_t k = 0; k < this->num_cols_; ++k) {
m3(i,j) += (*this)(i,k)*m2(k,j);
}
}
}
return m3;
}
Looking at the multiplication operator overload (please forgive the very slow matrix-matrix product implementation), the problem occurs when I try and define Matrix<float, rows, cols> m3. The error I get says error: non-type template argument is not a constant expression, which occurs because the dimensions of m3 are dependent on the dimensions of this and m2. However, it seems that template arguments have to be known at compile time, and therefore I can't use const size_t rows = this->num_rows_ and const size_t cols = m2.num_cols_ when instantiating m3.
As such, I'm not too sure how I can get the multiplication operator overload to work (and other operator overloads that require returning a new matrix as the result of the operation), since I'm unable to create a matrix to return. Is there a way to keep the current template (i.e. datatype, rows and cols), and still get the multiplication operator overload to work?
Make these two member variables static constexpr and initialize them from the template arguments, since they are just names for the template arguments there's no reason to store them in memory, they are known at compile time:
size_t num_rows_;
size_t num_cols_;
Also note that your copy constructor (and probably assignment operator) are pointless, the compiler would do the job for you if you didn't declare those.
Matrix operator*(const Matrix &m2) const;
this is wrong.
template<std::size_t Y>
Matrix<T, num_rows,Y> operator*(const Matrix<T, num_cols, Y> &m2) const;
this is correct..
Also, delete
size_t num_rows_;
size_t num_cols_;
or make them constexpr or enum constants.
The template multiplication operator will have the 3 dimensions as part of its template arguments.
// Multiplication operator overload
template<typename T, size_t num_rows, size_t num_cols>
template<size_t Y>
Matrix<T, num_rows, Y> Matrix<T, num_rows, num_cols>::operator*(const Matrix<T,num_cols,Y> &m2) const {
you know the cols/rows of each variable from their types.
I'm creating a simple C++ matrix template class, with the following definition:
template<uint n, uint m, typename T = double>
class Matrix {
private:
T data[n][m];
static Matrix<n, m, T> I;
public:
Matrix();
Matrix(std::initializer_list<T> l);
T& at(uint i, uint j); // one-based index
T& at_(uint i, uint j); // zero-based index
template<uint k> Matrix<n, k, T> operator*(Matrix<m, k, T>& rhs);
Matrix<m, n, T> transpose();
Matrix<n, m, T> operator+(const Matrix<n, m, T>& rhs);
Matrix<n, m, T>& operator+=(const Matrix<n, m, T>& rhs);
Matrix<n, m, T> operator-(const Matrix<n, m, T>& rhs);
Matrix<n, m, T>& operator-=(const Matrix<n, m, T>& rhs);
Matrix<n, m, T> operator*(const T& rhs);
Matrix<n, m, T>& operator*=(const T& rhs);
Matrix<n, m, T> operator/(const T& rhs);
Matrix<n, m, T>& operator/=(const T& rhs);
static Matrix<n, m, T> identity();
};
(uint is defined as an unsigned int)
The final function Matrix<n, m, T> identity() aims to return the static I member which is the identity matrix using a basic singleton pattern. Obviously the identity matrix is only defined for square matrices so I tried this:
template<uint n, typename T>
inline Matrix<n, n, T> Matrix<n, n, T>::identity() {
if (!I) {
I = Matrix<n, n, T>();
for (uint i = 0; i < n; ++i) {
I.at(i, i) = 1;
}
}
return I;
}
Which gives the error C2244 'Matrix<n,n,T>::identity': unable to match function definition to an existing declaration.
My impression was that I could do some sort of specialisation of the template where the number of columns and rows are equal. I'm not sure if this is even possible, but your help would be much appreciated.
Try this:
static Matrix<n, m> identity() {
static_assert(n == m, "Only square matrices have a identity");
return {}; //TODO
}
See: http://cpp.sh/7te2z
Partial specialization of a template class is allowed for the entire class, but not for its single member.
Members of partial specializations are not related to the members of the primary
template.
That is the reason behind your compilation error.
Of course, specializing the entire Matrix template for the square matrix case doesn't make sense. #tkausl has already answered how to make the identity() function available only for the square matrix types.
However, I would like to draw your attention toward a couple of issues in your implementation of Matrix:
The matrix data is a plain array (instead of a dynamically allocated array or std::vector). This has the following disadvantages:
sizeof(Matrix<N, M, T>) == sizeof(T)*N*M. Allocating large matrices on the stack may result in stack overflow.
Impossibility of taking advantage of move semantics (as the data is inseparable from the matrix object).
Though, if the matrix dimensions are fixed at compile time constants, then, most probably, they will be small numbers. If so, paying the cost of dynamic allocation may indeed be unjustified.
identity() returns its result by value (rather than by constant reference).
I (the identity matrix) is a static member of the class. It is better to make it a static variable inside the identity() function.
I have the following Matrix class that seems to be working well so far
template<typename T, std::size_t M, std::size_t N>
class Matrix
{
public:
Matrix(const std::initializer_list<std::initializer_list<T>> m)
{
// snip
}
T& operator()(const std::size_t i, const std::size_t j)
{
return m_data.at(i + j * N);
}
const T& operator()(const std::size_t i, const std::size_t j) const
{
return m_data.at(i + j * N);
}
Matrix<T,M,N> operator*(const T n)
{
// snip
}
private:
std::array<T, M * N> m_data;
};
However the overloaded operator* only allows scalar multiplication if the scalar is on the right hand side of the operator. I would like to allow this operation even if the scalar is on the left hand side of the operator, so I tried adding this to the Matrix.hpp file:
template<typename T, std::size_t M, std::size_t N>
Matrix<T,M,N> operator*(const T lhs, const Matrix<T,M,N> &rhs)
{
return rhs * lhs;
}
But this gives me the following error:
In file included from test.cpp:1:0:
Matrix.hpp: In instantiation of ‘Matrix<T, M, N> operator*(T, const Matrix<T, M, N>&) [with T = double; long unsigned int M = 3ul; long unsigned int N = 3ul]’:
test.cpp:21:13: required from here
Matrix.hpp:137:13: error: passing ‘const Matrix<double, 3ul, 3ul>’ as ‘this’ argument of ‘Matrix<T, M, N> Matrix<T, M, N>::operator*(T) [with T = double; long unsigned int M = 3ul; long unsigned int N = 3ul]’ discards qualifiers [-fpermissive]
return rhs * lhs;
If I remove const from the Matrix rhs parameter the code compiles and works correctly. I would like to understand why the code does not compile with the const in place?
You need to make the operator* free functions. (You'll need two of
them, one with the scalar on the right, and one with it on the left.)
You probably also want an operator*=; it may be convenient to use this
operator to implement the two operator*.
When you write operator as the member method then the first argument is always "this" instance of the class. If you want to write scalar * matrix then you must write the operator as non-member function. It is usually done as friend method.
template<typename T>
Matrix<T> operator*(T const& n, Matrix<T> m)
{
// snip
}
template<typename T>
Matrix<T> operator*(Matrix<T> m, T const& n)
{
return n * m;
}
I'm writing a 2D matrix template to learn templates and some C++11 features.
Wrote the following header:
template <class T, unsigned int Rows, unsigned int Columns>
class Matrix2D
{
private:
array<array<T,Columns>, Rows> m_Matrix;
public:
Matrix2D() {}
array<T,Columns>& operator[](unsigned int row) { return m_Matrix[row]; } ;
const array<T,Columns>& operator[](unsigned int row) const { return m_Matrix[row]; } ;
friend Matrix2D operator+ <> (const Matrix2D &lhs, const Matrix2D &rhs);
friend Matrix2D operator* <> (const Matrix2D &lhs, const Matrix2D &rhs);
};
The operator+ works fine - I have an implementation, it compiles, links, and stepped through with the debugger.
Problem is with operator*, for which I get the compilation error
1>...\matrix2d.h(18): error C2143: syntax error : missing ';' before '<'
1>...\matrix2d.h(19) : see reference to class template instantiation 'Matrix2D<T,Rows,Columns>' being compiled
There's no line of code trying to use the operator, so it's the definition itself which is wrong, I just don't understand why.
Can anyone help?
EDIT: (added from comment)
template <class T, unsigned int Rows, unsigned int Columns>
Matrix2D<T, Rows, Columns> operator+ (const Matrix2D<T, Rows, Columns> &lhs, const Matrix2D<T, Rows, Columns> &rhs)
{
Matrix2D<T, Rows, Columns> addResult;
for (unsigned int i = 0; i < Rows; i++)
for (unsigned int j = 0; j < Columns; j++)
addResult[i][j] = lhs[i][j] + rhs[i][j];
return addResult;
}
template <class T, unsigned int Rows, unsigned int Columns>
Matrix2D<T, Rows, Columns> operator* (const Matrix2D<T, lRows, lColumns> &lhs, const Matrix2D<T, rRows, rColumns> &rhs)
{
Matrix2D<T, lRows, rColumns> mulResult;
for(unsigned int i = 0; i < lRows; i++)
for(unsigned int j = 0; j < rColumns; j++)
for (unsigned int k = 0; k < lColumns; k++)
mulResult[i][k] += lhs[i][k] * rhs[k][j];
return addResult;
}
You cannot friend a specialization of an undeclared template function. Of course, declaring the operators before defining the class template will require you to forward declare it as well:
template <class T, unsigned int Rows, unsigned int Columns>
class Matrix2D;
template <class T, unsigned int Rows, unsigned int Columns>
Matrix2D<T, Rows, Columns>
operator+ (const Matrix2D<T, Rows, Columns> &lhs, const Matrix2D<T, Rows, Columns> &rhs);
template <class T, unsigned int Rows, unsigned int Columns>
Matrix2D<T, Rows, Columns>
operator* (const Matrix2D<T, Rows, Columns> &lhs, const Matrix2D<T, Rows, Columns> &rhs);
template <class T, unsigned int Rows, unsigned int Columns>
class Matrix2D
{
private:
array<array<T,Columns>, Rows> m_Matrix;
public:
Matrix2D() {}
array<T,Columns>& operator[](unsigned int row) { return m_Matrix[row]; }
const array<T,Columns>& operator[](unsigned int row) const { return m_Matrix[row]; }
friend Matrix2D operator+ <> (const Matrix2D &lhs, const Matrix2D &rhs);
friend Matrix2D operator* <> (const Matrix2D &lhs, const Matrix2D &rhs);
};
alternatively, you could take the easy way and define separate operator functions for each specialization of Matrix2D:
template <class T, unsigned int Rows, unsigned int Columns>
class Matrix2D
{
private:
array<array<T,Columns>, Rows> m_Matrix;
public:
Matrix2D() {}
array<T,Columns>& operator[](unsigned int row) { return m_Matrix[row]; }
const array<T,Columns>& operator[](unsigned int row) const { return m_Matrix[row]; }
friend Matrix2D operator+ (const Matrix2D &lhs, const Matrix2D &rhs) {
// do stuff that adds.
}
friend Matrix2D operator* (const Matrix2D &lhs, const Matrix2D &rhs) {
// do stuff that multiplies.
}
};
which I would probably use for the simpler overall syntax.
EDIT: Proper multiplication of non-square matrices means that the operator* function would in fact need to be friends of three different specializations of Matrix2D: the type of the left operand, right operand, and result. I think the first approach herein would become untenable. You should either friend all specializations of operator*:
template <class T, unsigned int Rows, unsigned int Columns>
class Matrix2D
{
// ...
template <typename U, typename V, unsigned Rows, unsigned Common, unsigned Columns>
friend Matrix2D<decltype(std::declval<U>()+std::declval<V>()), Rows, Columns>
operator * (const Matrix2D<U, Rows, Common>&,
const Matrix2D<V, Common, Columns>&);
};
or simply make the data public (probably the best approach for a "collection-of-data" class anyhow).
In:
template <class T, unsigned int Rows, unsigned int Columns>
class Matrix2D
{
// ...
friend Matrix2D operator* <> (const Matrix2D &lhs, const Matrix2D &rhs);
};
Matrix2D refer in fact to Matrix2D<T, Rows, Columns> .
And your operator * should be
template <T, unsigned Rows1, unsigned int Common, unsigned int Column>
Matrix2D<T, Row1, Column> operator* (const Matrix2D<T, Row1, Common>& lhs, const Matrix2D<T, Common, Column>& rhs);