Reputation: 483
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?
Upvotes: 0
Views: 73
Reputation: 275966
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.
Upvotes: 0
Reputation: 249642
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.
Upvotes: 0