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);
Related
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 have a template class of myMatrix mainly like:
template<class T, int row, int col>
class myMatrix{
T *_mat;
public:
template<int r, int c> using matrix_t = T[r][c];
myMatrix(const matrix_t<row, col> &);
myMatrix(const myMatrix<T, row, col> &);
myMatrix &operator=( const myMatrix<T, row, col>& );
//...
// next is the part of * overloading
myMatrix<T, row, col> operator*(const T& scalar);
typename< int c2 >
myMatrix<T, row, c2> operator*( const myMatrix<T, col, c2>& );
typename< int c2 >
myMatrix<T, row, c2> operator*( const matrix_t<col, c2>& );
typename< int r2 >
friend myMatrix<T, r2, col> operator*( const matrix_t<r2, row>&, const myMatrix<T, row, col>& );
// ...
};
Then I design another class Reference:
template<int dim, int loop>
class Reference{
myMatrix<int, dim, loop> _matA;
myMatrix<int, dim, 1> _matC;
public:
Reference(const myMatrix<int, dim, loop> &, const Matrix<int, dim, 1> &);
Reference(const Reference<dim, loop> &);
Reference<dim, loop> &operator=(const Reference<dim, loop> &);
// ...
friend Reference<1, loop> operator*(const Matrix<int, 1, dim> &alpha,
const Reference<dim, loop> & ref)
{
return Reference(alpha * ref._matA, alpha * ref._matC); // **Problem!!!**
}
// ...
};
When I test the codes with something like
const int matA[3][3] = {1,2,3,4,5,6,7};
const int matC[3][1] = {1,2,3};
const int alp[][3] = {1,2,2};
Reference<3,3> ref(matA, matC);
Matrix<int, 1, 3> alpha(alp);
// Reference<1,3> ref_t = alp * ref;
Reference<1,3> ref_t = alpha * ref; // **can not compile!!!**
The problem occurs:
binary '*': no operator found which takes a left-hand operand of type 'const myMatrix' ( or there is no acceptable conversion )...
Then here come my questions:
Of all the +4 overloadings in class myMatrix, if there are any redundancies?
Maybe just the overloading version of typename< int c2 > myMatrix<T, row, c2> operator*( const myMatrix<T, col, c2>& ); can service the following two overloads since a built-in 2d-array like arr[][] can convert to a myMatrix due to my constructor myMatrix(const matrix_t<row, col> &);?
What is the reason for the compiling error?
The compiler error says what you've done wrong:
binary '*': no operator found which takes a left-hand operand of type 'const myMatrix'
You have
operator*(const myMatrix&);
but no
operator*(const myMatrix&) const;
So alpha * ref can't match (because alpha is const&).
The usual way to implement T::operator* is
T& operator*=(const T&);
T operator*(const T&) const;
Or (better), make the * operator a free function with two arguments (this can work better if you might need to promote the left-hand argument).
Seriously, I looked at similar examples, but I still do not get why it is not working. I am having trouble with overloading the = operator.
I get the two following errors:
error C2955: 'Matrix' : use of class template requires template argument list
error C2244: 'Matrix::operator =' : unable to match function definition to an existing declaration
May someone please explain what is wrong?
Thanks to all
//Matrix.hpp
template<typename T>
class Matrix
{
public:
Matrix(int numberRows, int numberColumns);
~Matrix();
void asgValue(T value, int row, int column);
T getValue(int row, int column);
Matrix<T>& operator= (const Matrix<T>& rhs);
friend Matrix<T>& operator+ (const Matrix<T>& lhs, const Matrix<T>& rhs);
private:
T **twoDarray;
int nbrRows;
int nbrColumns;
};
#include "Matrix.inl"
//Matrix.inl
//Matrix<T>& Matrix<T>::operator= (const Matrix<T>& rhs)
template<typename T>
Matrix<T>& Matrix::operator= (const Matrix<T>& rhs)
{
for (int i = 0; i < nbrRows; i++)
{
for (int j = 0; j < nbrColumns; j++)
{
twoDarray[i][j] = rhs.twoDarray[i][j];
}
}
return *this;
}
You need template parameters in the name of the function being defined.
template<typename T>
Matrix<T>& Matrix<T>::operator= (const Matrix<T>& rhs)
// ^ here
You are required to write <T>, although it doesn't add to the expressiveness of the language — the arguments before :: cannot be anything other than the entire class template parameter list in the original order and without any modifications. It is what it is.
I have a class that simulates 2D matrix through the use of nested vectors as follows:
In the class header file this is what I have:
template <typename T> class L1Matrix {
private:
std::vector<std::vector<T> > mat;
unsigned rows;
unsigned cols;
public:
L1Matrix(); /* emptry constructor */
L1Matrix(unsigned _rows, unsigned _cols, const T& _initial);
L1Matrix(const L1Matrix<T>& rhs);
virtual ~L1Matrix();
T& operator()(const unsigned& row, const unsigned& col);
const T& operator()(const unsigned& row, const unsigned& col) const;
}
In the class declaration this is what I have:
// default constructor
template<typename T>
L1Matrix<T>::L1Matrix() : rows(0), cols(0) {};
template<typename T>
L1Matrix<T>::L1Matrix(unsigned _rows, unsigned _cols, const T& _initial) {
mat.resize(_rows);
for (unsigned i=0; i<mat.size(); i++) {
mat[i].resize(_cols, _initial);
}
rows = _rows;
cols = _cols;
}
template<typename T>
L1Matrix<T>::L1Matrix(const L1Matrix<T>& rhs) {
mat = rhs.mat;
rows = rhs.get_rows();
cols = rhs.get_cols();
}
template<typename T>
std::vector<std::vector<T> >::reference L1Matrix<T>::operator()(const unsigned& row, const unsigned& col) {
return this->mat[row][col];
}
For sake of brevity I am not giving the rest of the class implementation here.
Now in the main code I am creating pointer to this 2D matrix as follows:
L1Matrix<bool>* arr1; // this is pointer to L1Matrix object
L1Matrix<int> arr2(XSize, YSize, 0); // L1Mtarix object
arr1 = new L1Matrix<bool>(XSize, YSize, true);
Now for the actual L1Matrix object arr2 I can access the individual rows and columns like this: arr2(row,col) but my question is how to access the similar row and column elements using the L1Matrix pointer object arr1?
Please let me know.
Thanks
You should be able to use (*arr1)(row, col)
I asked a question earlier yesterday and got some very good answers for sure.
Now I am at the end of my project and I am stuck again and can't figure out the answer.
I am going to put the most pertinent part of my code here and hope to get some insight from you all.
The requirements are: I cannot change the code in my main.cpp, and my header file is supposed to be as simple as possible.
Having that out of the way here is the code: This is my Matrix.h file
#ifndef MATRIX_H
#define MATRIX_H
#include <vector>
#include <iostream>
#include <math.h>
#include <complex>
using namespace std;
namespace theMatrix {
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];
};
vector<T> & operator[](int ROWS) {
return elts[ROWS];
};
//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++) {
this->elts[i][j] += mat1.elts[i][k] * mat2.elts[k][j];
}
}
}
return *this;
};
//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;
};
//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>
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 matrixMult
template <typename T, size_t ROWS, size_t INNER, size_t COLS>
inline void matrixMult(const Matrix<T, ROWS, INNER> & mat1, const Matrix<T, INNER, COLS> & mat2, Matrix<T, ROWS, COLS> & mat3) {
mat3 = matrixMult(mat1, mat2);
};
This is my main.cpp:
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib> // for rand()
#include "Matrix.h"
using namespace std;
using namespace theMatrix;
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()
{
// Matrix multiplication tests:
Matrix<int, 2, 3> m4;
randomize(m4);
Matrix<int, 3, 5> m5;
randomize(m5);
Matrix<int, 2, 5> m6;
Matrix<int, 2, 5> m7;
matrixMult(m4, m5, m7);
out << "m6 == m4 * m5: " << (m6 == m4 * m5) << endl; // here is the first error
// Matrices of Complex:
Matrix<Complex, 2, 8> m11;
randomize(m11);
Complex c(1, -3);
Matrix<Complex, 8, 3> m12;
randomize(m12);
out << "m11 * m12: " << endl << m11 * m12 << endl; // Here is the second error
out.close();
}
I am having only two errors which are conflicting with the complex operator * declaration which I have been trying to solve for several hours and I just can't figure it out.
Here are the errors:
Error 1 error C2678: binary '*' : no operator found which takes a left-hand operand of type 'nkumath::Matrix<T,ROWS,COLS>' (or there is no acceptable conversion)
Error 2 error C2678: binary '*' : no operator found which takes a left-hand operand of type 'nkumath::Matrix<T,ROWS,COLS>' (or there is no acceptable conversion)
Thanks again for everyone's help on this.
EDIT: Here is the solution! which I voted for. Thanks!!!
//Operator*
template <typename 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) {
Matrix<T, ROWS, COLS> returnVal;
return returnVal.matrixMult(lhs, rhs);
};
Your templated operator * overload does not allow the two input matrices to differ in size.
Your problem is that the templated operator* requires both sides of the multiplication to be the same Matrix instantiation. T, ROWS and COLS can't be deduced to different values for the type of lhs and rhs in the same function.
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<int, 2, 3> m4;
Matrix<int, 3, 5> m5;
m4*m5;
If the compiler deduces ROWS and COLS as 2 and 3 for the above multiplication, the rhs type won't match your templated operator*. And if the compiler deduces ROWS as 3 and COLS as 5, the lhs type won't match.
You'll need to define how multiplication of differently sized Matrix instances should work, and make e.g:
template <typename T, size_t ROWS_L, size_t COLS_L, size_t ROWS_R, size_t COLS_R>
Matrix<T, ROWS_L, COLS_L> operator*(const Matrix<T, ROWS_L, COLS_L> & lhs, const Matrix<T, ROWS_R, COLS_R> & rhs);