I've got a Matrix class. It's a template with type, rows and cols for static allocation of small matrix. The problem is with the overload of operator* and operator*=. In this case the operation must be granted for a different object: same type, rows equals to my column and a number of columns. I wrote this code now and it works, but I wonder if I can force to use the same type T instead of having another type T1. Same thing for rows and columns.
template<typename T, int R, int C>
class Matrix {
private:
//some data.....
public:
//some methods.....
template <typename T1, int R1, int C1> <----here I'd like to use T as type
Matrix<T,R,C1> operator*(const Matrix<T,R1,C1>& rhs);
template <typename T1, int R1, int C1>
Matrix<T,R,C1>& operator*=(const Matrix<T,R1,C1>& rhs);
}
For operator *, the template parameters don't have to match the function arguments, so you can just leave it out. Also, there is a restriction that the number of rows of the second matrix match the number of columns of the first matrix, so you really only need one template parameter:
template<typename T, int R, int C>
class Matrix {
private:
//some data.....
public:
//some methods.....
template <int C1>
Matrix<T,R,C1> operator*(const Matrix<T,C,C1>& rhs) const;
};
operator *= can only work with square matrices, so you have to be careful there.
template<typename T, int R, int C>
class Matrix {
private:
//some data.....
public:
//some methods.....
template <int C2>
Matrix<T,R,C2> operator*(const Matrix<T,C,C2>& rhs);
Matrix& operator*=(const Matrix<T,C,C>& rhs);
}
You can just use the template arguments from the enclosing class, no worry.
Anyway, I reduced both operators to what matrix-multiplication actually allows.
Related
I am writing a matrix class template. I want to implement the multiplication or addition of different types of matrices( for example, between real and imaginary matrices ), but I cannot access the data members of another type of matrix. How should I solve this problem?
template <class Type>
class Matrix
{
Type** p_data; //Represents matrix data
int row, col; //Represents the number of rows and columns of the matrix
public:
Matrix(int r, int c);
~Matrix();
Matrix(Type *data, int row, int col);
Type* operator[] (int i);
// Overload [], for Matrix object M, can be accessed by M [I] [J] to
// access the i + 1 line, the J + 1 column element
Matrix &operator = (const Matrix& m);
// Overload =, implement matrix overall assignment, if the row / column does not wait,
// return space and reassign
bool operator == (const Matrix& m) const; //Overload ==, determined whether the matrix is equal
template <class Type1>
Matrix operator + (const Matrix<Type1>& m) const;
// Overload +, complete matrix addition, can assume
// that the two matrices meet the addition conditions (the rows, the columns are equal)
template <class Type1>
Matrix operator * (const Matrix<Type>& m) const;
// Overload *, complete matrix multiplication, can assume that two matrices meet multiplication
// conditions (this.col = m.row)
template <class Type1>
friend std::ostream& operator << (std::ostream& out,Matrix<Type1>& c);
};
template<class Type>
template <class Type1>
Matrix<Type> Matrix<Type>::operator + (const Matrix<Type1>& m) const{
Matrix<Type> res(row,col);
for(int i=0;i<row;++i)
for(int j=0;j<col;++j)
res.p_data[i][j] =p_data[i][j] + m.p_data[i][j]; // error in this line
return res;
}
You can use a friend declaration
template <typename T>
class Matrix
{
template <typename U>
friend class Matrix;
// ...
};
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;
}
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'm trying to make a reusable matrix class with the dimensions and type given in the template arguments. The struct itself is just:
template <unsigned int N, unsigned int M, typename T>
struct Matrix
{
T elements[N* M];
};
When I tried to implement matrix multiplication, I came to a problem that I need to introduce new template arguments. The size of the original matrix is N * M. The size of the second matrix is L * N and the result matrix is N * K. So the multiply function would look something like:
Matrix<N, K, T> Multiply(const Matrix<L, N, T>& other) {... }
But then I need to create a template for the function, so calling would become mat.Multiply<x, y>(mat2), which means that I have to specify things twice. Is there a way to avoid this? (something like Matrix<N, unsigned int K, T>)
Edit: I've tried this:
template <unsigned int K, unsigned int L>
Matrix<N, K, T> Multiply(const Matrix<L, N, T>& other)
And with this code I get an error saying no instance of function template matches the argument list:
Matrix<3, 2, int> mat;
Matrix<2, 3, int> mat2;
mat.Multiply(mat2)
By the way I'm using MSVC and Visual Studio.
so calling would become mat.Multiply<x, y>(mat2)
If the multiplication member function were a function template like so
template <unsigned int N, unsigned int M, typename T>
struct Matrix
{
template <unsigned int L>
Matrix<N, L, T> Multiply(const Matrix<M, L, T>& other) {... }
T elements[N * M];
};
then template argument deduction allows you to call the function like this:
mat.Multiply(mat2)
Note: you should probably consider implementing a non-member operator* too, to allow for this:
auto mat3 = mat * mat2;
It is normal that Multiply is also template.
Note that K == L for a multiplication.
template <unsigned int N, unsigned int M, typename T>
struct Matrix
{
template <unsigned int K>
Matrix<N, K, T> Multiply(const Matrix<M, K, T>& other) const {/*..*/}
T elements[N* M];
};
In the call, all template argument are deducible so you can call it that way:
int main()
{
const int N = 4;
const int M = 5;
const int K = 6;
using T = float;
Matrix<N, M, T> rhs;
Matrix<M, K, T> lhs;
Matrix<N, K, T> res = rhs.Multiply(lhs);
}
I wrote a generic matrix class like so:
template <std::size_t N, std::size_t M, class T>
class CMatrix
{
protected:
T* m_elem;
public:
CMatrix() : m_elem(new T[N*M]) {}
~CMatrix() { delete[] m_elem; }
inline bCMatrix& operator*=(const T& val);
inline bCMatrix& operator/=(const T& val);
...
template <std::size_t L> inline CMatrix<L, N, T> operator*(const CMatrix<M, L, T>& mat) const;
};
Now I would like to make several specializations for CMatrix<2,2,T>.
I'd like to add a comstructor CMatrix<2,2,T>(const T& a00, const T& a01, const T& a10, const T& a11) {...}.
And I like to specialize the matrix multiplication for CMatrix<2x2>*CMatrix<2x2>. But on the other hand I'd like to keep the functionalities of *= and /= and so on.
How would I do so?
My only working attempt is to rewrite (copy/past/search/replace) all the code for the specialization N=3, M=3, like:
template <class T>
class CMatrix<3,3,T>
{
...
};
Now I can specialize the matrix-matrix multiplication for 2x2. But I have two nearly identical pieces of code, like one for the generic matrix-vector multiplication and one for the matrix-vector multiplication with matrix 2x2. Which both have to be changed if I optimize the generic one. Sucks to maintain that.
You can read some documentation on class template, such as http://en.cppreference.com/w/cpp/language/partial_specialization. For you it entails defining the specialization in a way like this:
template<typename T>
class CMatrix<2, 2, T>
{
public:
CMatrix<2,2,T>(const T& a00, const T& a01, const T& a10, const T& a11);
...
template <std::size_t L> inline CMatrix<L, 2, T> operator*(const CMatrix<2, L, T>& mat) const;
// Special overload for 2x2 x 2x2 multiplication
inline CMatrix<2, 2, T> operator*(const CMatrix<2, 2, T>& mat) const;
};
To prevent duplication of code for operator*= etc you can make a template<int M, int N, typename T> class CMatrixBase {} and implement them in there, and have your actual matrix classes and specializations inherit from that.
Martin suggested to use CRTP, which helps you to not lose your type information. This would look like this:
template<int M, int N, typename T, typename Derived>
class CMatrixBase
{
public:
Derived& operator*=(T val) {
doMultiplication(val);
return *static_cast<Derived*>(this);
}
};