Multi-overloading of operator* in template matrix class - c++

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).

Related

Can't multiply two matrices, where hight and width are defined by template

I wrote Class Matrix, parameters of which I define by template. So when I tried to declare operator* between two matrices, I found out? that Cpp counts matrices with different parameters as different classes (For example 7x3 and 3x5). How can I avoid this?
Here is my class
template <size_t N, size_t M, typename T = int64_t>
class Matrix {
public:
Matrix();
Matrix(std::vector<std::vector<T>> const input);
Matrix(const T elem);
Matrix operator+(const Matrix& other) const;
Matrix& operator+=(const Matrix& other);
Matrix operator-(const Matrix& other) const;
Matrix& operator-=(const Matrix& other);
Matrix operator*(const T& other) const;
Matrix& operator*=(const T& other);
Matrix operator*(const Matrix& other) const;
Matrix& operator*=(const Matrix& other);
Matrix Transposed();
T Trace();
T& operator()(const size_t i, const size_t j) const;
bool operator==(const Matrix& other) const;
private:
};
Cppref did not helped :(
Template arguments are part of the type; otherwise they couldn't be considered in type resolution and SFINAE. Thus, there are two choices:
either make N, M runtime arguments of e.g. Matrix (or can even be deduced from current input), thereby making it non-template, or
you live with the fact that the concrete class depends on N, M and, optionally, you might have a base class where this part of the type is erased; or, if you don't need a common base type, you might have the operator as a template and then you might have a different Matrix on the rhs.
The latter can be like this:
typename<T = int64_t>
class Matrix {
Matrix();
Matrix(std::vector<std::vector<T>> const input);
Matrix(const T elem);
// other operators, functions
virtual Matrix operator*(const Matrix& other) const;
};
template <size_t N, size_t M, typename T = int64_t>
class FixedSizeMatrix : Matrix<T> {
// as now, possibly with override when appropriate
Matrix<N, M1> operator*(const Matrix& other) const override /* final? */;
};
However, this will be slower, due to virtual resolution. If you don't need a common base:
template <size_t N, size_t M, typename T = int64_t>
class Matrix {
public:
// as before
template<size_t N1, size_t M1, typename T2 = int64_t>
Matrix operator*(const Matrix<N1, M1, T2>& other) const;
};
Main question to ask yourself is, why you want `N, M` to be compile-time arguments.

Implicit conversion class templates

I am trying to implement a Matrix class with linear algebraic operations. I want to make the class available for a few value types like uint, uchar, float, double.
The header looks as follows:
template<typename T>
class Matrix{
public:
Matrix(int width, int height);
Matrix(const Matrix<T> & other);
virtual ~Matrix();
unsigned int width() const { return width_; }
unsigned int height() const { return height_; };
T * data() const { return data_ptr_; };
private:
T * data_ptr_;
unsigned int width_;
unsigned int height_;
}
The source file looks as follows.
template<typename T>
Matrix<T>::Matrix(int width, int height ): width_(width), height_(height)
{
data_ptr_ = new T[width * height];
}
template<typename T>
Matrix<T>::Matrix(const Matrix<T> & other): Matrix(other.width(), other.height() )
{
memcpy(data_ptr_, other.data(), width_ * height_ * sizeof(T);
}
template<typename T>
Matrix<T>::~Matrix()
{
delete []data_ptr_;
}
template class Matrix<double>;
template class Matrix<float>;
...
Now I want to define an operator + which will return a Matrix of the type which an ordinary c++ conversion does when adding two values, i.e.
Matrix<double> + Matrix<float> => Matrix<double>
Matrix<int> + Matrix<float> => Matrix<float>
and I want to be able to do this without explicit conversions. For example
Matrix<float> float_matrix(10,20);
Matrix<int> int_matrix(10,20);
auto sum_matrix = float_matrix + int_matrix;
so the sum should have type float.
I tried 2 methods with no success, however.
Method 1
Define operator + as
//inside class definition
Matrix<T> operator+(const Matrix<T> &other) const;
and define implicit constructors like
//inside the class declaration
template<typename K>
Matrix(const Matrix<K> & other);
and instantiate them only in the obvious hierarchical order:
uchar-> uint->float->double, however I still have to manually cast operands of different types.
Method 2
Define operator + as
//inside the class declaration
template<typename K, typename R>
Matrix<R> operator+(const Matrix<K> &other) const;
and write specializations for each case, however, I could not get the compiler to correctly deduce the template arguments.
Neither of methods seem to be correct.
Can anyone point me a direction?
You can use method 3 and use C++11's auto return type deduction to figure out the type for you. Using
template<typename K>
auto operator+(const Matrix<K> &other) const -> Matrix<decltype(std::declval<T>() + std::declval<K>())>;
This says that the matrix returned will have the type of whatever a T added to a K would be.
You won't be able to make custom rules with this but it will follow the standard promotion/conversion rules.
Variant of the method 3 from MathanOliver: define operator+() (off topic suggestion: ever define operator+=() as method and operator+() as external function) not as method but as external function (you can make it friend to Matrix if needed).
template <typename T1, typename T2,
typename Tr = decltype(std::declval<T1>() + std::declval<T2>())>
Matrix<Tr> operator+ (Matrix<T1> const & m1, Matrix<T2> const & m2)
{
// something useful
return {m1.width(), m1.height()};
}
The following is a full compiling example
#include <cstring>
#include <utility>
template <typename T>
class Matrix
{
public:
Matrix(unsigned int width, unsigned int height)
: width_(width), height_(height)
{ data_ptr_ = new T[width * height]; }
Matrix(const Matrix<T> & other)
: Matrix(other.width(), other.height() )
{ std::memcpy(data_ptr_, other.data(), width_ * height_ * sizeof(T)); }
virtual ~Matrix()
{ delete []data_ptr_; }
unsigned int width() const
{ return width_; }
unsigned int height() const
{ return height_; };
T * data() const
{ return data_ptr_; };
private:
T * data_ptr_;
unsigned int width_;
unsigned int height_;
};
template <typename T1, typename T2,
typename Tr = decltype(std::declval<T1>() + std::declval<T2>())>
Matrix<Tr> operator+ (Matrix<T1> const & m1, Matrix<T2> const & m2)
{
return {m1.width(), m1.height()};
}
int main ()
{
Matrix<int> m1{1, 2};
Matrix<float> m2{1, 2};
auto m3 = m1 + m2;
auto m4 = m2 + m1;
static_assert( std::is_same<decltype(m3), Matrix<float>>{}, "!" );
static_assert( std::is_same<decltype(m4), Matrix<float>>{}, "!" );
return 0;
}
Obtaining the type of the returned matrix as default template value (Tr) you can explicit a different type, if you want, as follows
auto m5 = operator+<int, float, int>(m1, m2);
static_assert( std::is_same<decltype(m5), Matrix<int>>{}, "!" );

C++ operator* overloading

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;
}

Overloading templated class binary operator*

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

Templates and lose of information

I created a matrix class:
template <typename T>
class Matrix
{
public:
Matrix(size_t n_rows, size_t n_cols);
Matrix(size_t n_rows, size_t n_cols, const T& value);
void fill(const T& value);
size_t n_rows() const;
size_t n_cols() const;
void print(std::ostream& out) const;
T& operator()(size_t row_index, size_t col_index);
T operator()(size_t row_index, size_t col_index) const;
bool operator==(const Matrix<T>& matrix) const;
bool operator!=(const Matrix<T>& matrix) const;
Matrix<T>& operator+=(const Matrix<T>& matrix);
Matrix<T>& operator-=(const Matrix<T>& matrix);
Matrix<T> operator+(const Matrix<T>& matrix) const;
Matrix<T> operator-(const Matrix<T>& matrix) const;
Matrix<T>& operator*=(const T& value);
Matrix<T>& operator*=(const Matrix<T>& matrix);
Matrix<T> operator*(const Matrix<T>& matrix) const;
private:
size_t rows;
size_t cols;
std::vector<T> data;
};
Now I want to enable operations between matrix of different types, for example:
Matrix<int> matrix_i(3,3,1); // 3x3 matrix filled with 1
Matrix<double> matrix_d(3,3,1.1); // 3x3 matrix filled with 1.1
std::cout << matrix_i * matrix_d << std::endl;
I thought to do like this (is the right way?):
template<typename T> // Type of the class instantiation
template<typename S>
Matrix<T> operator*(const Matrix<S>& matrix)
{
// Code
}
I think this will work fine if I multiply a double matrix with an integer matrix: I will obtain a new double matrix. The problem is that if I multiply an integer matrix with a double matrix I will lose some information, because the matrix I obtain will be an integer matrix... Right? How can I fix this behave?
std::cout << matrix_d * matrix_i << std::endl; // Works: I obtain a 3x3 matrix full of 1.1
std::cout << matrix_i * matrix_d << std::endl; // Doesn't work: I obtain a 3x3 matrix full of 1 instead of 1.1
To do what you want, you will need to offer an operator* that returns a Matrix<X> where X is the type with the largest range/greatest precision.
If you have a C++11 compiler at hand, you could use:
template <typename T, typename U>
auto operator*( Matrix<T> const & lhs, Matrix<U> const & rhs)
-> Matrix< delctype( lhs(0,0) * rhs(0,0) ) >
{
Matrix< delctype( lhs(0,0) * rhs(0,0) ) > result( lhs );
result *= rhs;
return result;
}
Assuming that you have operator*= implemented as a template that allows multiplications with other instantiations of Matrix<T> and that you have a conversion constructor.