Inheriting everything from base class - c++

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>();

Related

Operator overload error in class template due to template arguments not being constant expressions

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.

Partial template specialization to unroll loops for specific sizes

I have written a matrix class which can take different sizes. Now I want to unroll loops for specific sizes. How should I do this?
The only way I can seem to get working is a child-class for 2-d. But this I would like to avoid, as it would result in much duplicate code.
For example:
#include <iostream>
template<class T, size_t M, size_t N>
class matrix
{
matrix<T,M,N>& operator*= (const matrix<T,M,N> &B);
};
template<class T, size_t M, size_t N>
matrix<T,M,N>& matrix<T,M,N>::operator*= (const matrix<T,M,N> &B)
{
// ...
return *this;
}
int main()
{
return 0;
}
Now I would like to add an implementation for the case that M = 2 and N = 2 where I unroll all loops to gain efficiency.
(I have timed the unroll in a previous implemenation, and it really does seem to make sense, in particular for more complicated operations then featured in this example.)
You can delegate operator*= to an overloaded function template. E.g.:
template<class T, size_t M, size_t N>
class matrix
{
public:
matrix<T,M,N>& operator*=(const matrix<T,M,N>&);
};
// Generic version.
template<class T, size_t M, size_t N>
void inplace_dot(matrix<T,M,N>& a, matrix<T,M,N> const& b);
// Overload for 2x2 matrix.
template<class T>
void inplace_dot(matrix<T,2,2>& a, matrix<T,2,2> const& b);
template<class T, size_t M, size_t N>
matrix<T,M,N>& matrix<T,M,N>::operator*=(const matrix<T,M,N>& b)
{
inplace_dot(*this, b);
return *this;
}

C++ template matrix class - square matrix specialisation

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.

Template Matrix-Matrix multiplication c++

I am trying to do Matrix-Matrix multiplication with template and I keep getting following error. ( I am trying to multiply non-square matrix)
Error 1 error C2593: 'operator *' is ambiguous
Can any one give me an advice on how to fix this?
//Matrix.h
#pragma once
#include <iostream>
#include <vector>
using namespace std;
template<class T, int m, int n>
class Matrix;
template<class T, int m, int n, int l>
Matrix<T, m, n> operator*(const Matrix<T, m, n>&, const Matrix<T, n, l>&);
template<class T, int m, int n>
class Matrix
{
vector<vector<T>> elements;
int nrow;
int ncol;
public:
Matrix();
~Matrix();
void print();
template<int l>
friend Matrix<T, m, l> operator*<>(const Matrix<T, m, n>&, const Matrix<T, n, l>&);
};
template<class T, int m, int n>
Matrix<T, m, n>::Matrix() : nrow(m), ncol(n)
{
for (int i = 0; i < nrow; i++){
vector<T> row(ncol, i);
elements.push_back(row);
}
}
template<class T, int m, int n>
Matrix<T, m, n>::~Matrix(){}
template<class T, int m, int n>
void Matrix<T, m, n>::print()
{
for (int i = 0; i < nrow; i++){
for (int j = 0; j < ncol; j++){
cout << elements[i][j] << " ";
}
cout << endl;
}
}
template<class T, int m, int n, int l>
Matrix<T, m, l> operator*(const Matrix<T, m, n>& m1, const Matrix<T, n, l>& m2){
int nrow = m1.nrow;
int ncol = m2.ncol;
Matrix<T, m, l> m3;
for (int i = 0; i < nrow; ++i){
for (int j = 0; j < ncol; ++j){
m3.elements[i][j] = 0;
for (int k = 0; k < m1.ncol; k++){
T temp = m1.elements[i][k] * m2.elements[k][j];
m3.elements[i][j] = temp + m3.elements[i][j];
}
}
}
return m3;
}
//main.cpp
#include "Matrix.h"
using namespace std;
int main()
{
Matrix<int, 3, 2> a;
Matrix<int, 2, 1> b;
Matrix<int, 3, 1> c;
c = a*b;
c.print();
}
The problem occurs in the matrix multiplication possibly due to the coding error in the template.
I had to change what Richard changed, but I also had to change the declaration of operator* and the friend as follows:
template<class T, int m, int n, int l>
Matrix<T, m, l> operator*(const Matrix<T, m, n>&, const Matrix<T, n, l>&);
// ^ here
and:
template<class _T, int _m, int _n, int l>
friend Matrix<_T, _m, l> operator*(const Matrix<_T, _m, _n>&, const Matrix<_T, _n, l>&);
I got the "operator* is ambiguous" error if I didn't change the first of these two, since the forward declaration doesn't match the instantiation further down.
It's currently outputting:
0
1
2
That doesn't seem quite right, but I'm not awake enough to debug further.
The error is here:
./matrix.cpp:48:28: error: function template partial specialization is not allowed
friend Matrix<T, m, l> operator*<>(const Matrix<T, m, n>&, const Matrix<T, n, l>&);
^ ~~
1 error generated.
change it to this:
friend Matrix<T, m, l> operator*(const Matrix<T, m, n>&, const Matrix<T, n, l>&);

C++: ambigous overload can be resolved if typedefs are replaced

Consider the following code snippet for vector and matrix multiplication:
#include <array>
template<typename T,size_t N> using vec = std::array<T,N>;
template<typename T,size_t N,size_t M> using mat = vec<vec<T,M>,N>;
template<typename T,typename U,size_t N>
vec<T,N> operator*(const vec<T,N>& a,const vec<U,N>& b){
return {}; //implement componentwise mult.
}
template<typename T,typename U,size_t N,size_t M,size_t L>
mat<T,L,M> operator*(const mat<T,N,M>& a,const mat<U,L,N>& b){
return {}; //implement matrix mult.
}
int main(){
mat<float,4,4> a,b;
auto c = a * b;
}
I define 2 operator* overloads, where the second one explicitly uses matrices.
This will result in an "ambigous overload" error on GCC 5.2, although in my opinion the second overload is more specialized than the first one.
I now replace the typedefs in the second overload:
mat<T,L,M> operator*(const mat<T,N,M>& a,const mat<U,L,N>& b)
becomes:
mat<T,L,M> operator*(const vec<vec<T,M>,N>& a,const vec<vec<U,N>,L>& b)
Edit:
I made a small typo... thats why the resolution worked, I swapped N and L, so the type of b was const vec<vec<U,L>,N>& b.
Only with this typo the overload can be resolved normally.
My question is: Is this behavior welldefined by the standard or a bug?
With VS2015:
your code
template<typename T, typename U, size_t N>
vec<T, N> operator*(const vec<T, N>& a, const vec<U, N>& b) {
return{}; //implement componentwise mult.
}
template<typename T, typename U, size_t N, size_t M, size_t L>
mat<T, L, M> operator*(const mat<T, N, M>& a, const mat<U, L, N>& b) {
return{}; //implement matrix mult.
}
results in
Error C2593 'operator *' is ambiguous
Ambiguity derives from the fact that in vec<T, N> operator*(const vec<T, N>& a, const vec<U, N>& b) T can be interpreted as a vec<T,M>.
And if I replace them as you suggested with
template<typename T, typename U, size_t N>
vec<T, N> operator*(const std::array<T, N>& a, const std::array<U, N>& b) {
return{}; //implement componentwise mult.
}
template<typename T, typename U, size_t N, size_t M, size_t L>
mat<T, L, M> operator*(const vec<vec<T, M>, N>& a, const vec<vec<U, N>, L>& b) {
return{}; //implement matrix mult.
}
the results doesn't change.
Error C2593 'operator *' is ambiguous
Are you sure about your solution? Maybe you are not considering const?