Templates and lose of information - c++

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.

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.

matrix class template,the multiplication or addition of different types of matrices

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

Mix concrete and non-concrete types in templates C++

My problem is somewhat like partial specification in a template class C++.
I write a template<class T> class matrix to carry some matrix computation. For this class I define overloaded comparison operators such as ==, >=, <=. I want this snippet of code
matrix<float> a(2,3), b(2,3);
a.fill(1); b.fill(2);
matrix<bool> c = (a == b);
results in a boolean matrix c having the same size of a and b and that c(i,j)<-true iff a(i,j) == b(i,j) . With the following code this could not be done
template<class T>
class matrix
{
public:
matrix ();
matrix (size_t rows, size_t cols);
matrix (const matrix<T>& mx);
size_t rows() const;
size_t cols() const;
size_t size() const;
const T* ptr() const;
T* mutable_ptr();
// etc
private:
size_t num_rows;
size_t num_cols;
vector<T> data;
}
template<class T> const T* matrix<T>::ptr() const { return data.data(); }
template<class T> T* matrix<T>::mutable_ptr() { return data.data(); } // line **459**
template<class T> matrix<bool>& operator< (const matrix<T>& mx, const T t);
template<class T> matrix<bool>& operator<= (const matrix<T>& mx, const T t);
template<class T> matrix<bool>& operator> (const matrix<T>& mx, const T t);
template<class T> matrix<bool>& operator>= (const matrix<T>& mx, const T t);
template<class T> matrix<bool>& operator== (const matrix<T>& mx, const T t);
template<class T> matrix<bool>& operator!= (const matrix<T>& mx, const T t);
// ...
template<class T> matrix<bool>& operator== (const matrix<T>& mx, const T value) { // line **547**
matrix<bool> *index = new matrix<bool>(mx.rows(), mx.cols());
const T *ptr = mx.ptr();
bool *ptr_i = index->mutable_ptr();
size_t m = mx.size();
for (size_t i=0; i < m; ++i) {
if (ptr[i] == value)
ptr_i[i] = true;
else
ptr_i[i] = false;
}
return *index;
}
The compiler outputs
matrix.hpp: In member function ‘T* matrix<T>::mutable_ptr() [with T = bool]’:
matrix.hpp:547:35: instantiated from ‘matrix<bool>& operator==(const matrix<T>&, T) [with T = float]’
compute_sil.cpp:163:26: instantiated from here
matrix.hpp:459:66: error: void value not ignored as it ought to be
Is there any way to overcome this?
EDIT
Sorry to put not enough codes, I did overload of operators with many argument types, between a matrix vs. scalar, and between matrices too.
template<class T> matrix<bool>& operator< (const matrix<T>& mx, const matrix<T>& mx2);
template<class T> matrix<bool>& operator<= (const matrix<T>& mx, const matrix<T>& mx2);
template<class T> matrix<bool>& operator> (const matrix<T>& mx, const matrix<T>& mx2);
template<class T> matrix<bool>& operator>= (const matrix<T>& mx, const matrix<T>& mx2);
template<class T> matrix<bool>& operator== (const matrix<T>& mx, const matrix<T>& mx2);
template<class T> matrix<bool>& operator!= (const matrix<T>& mx, const matrix<T>& mx2);
template<class T> matrix<bool>& operator< (const T t, const matrix<T>& mx);
template<class T> matrix<bool>& operator<= (const T t, const matrix<T>& mx);
template<class T> matrix<bool>& operator> (const T t, const matrix<T>& mx);
template<class T> matrix<bool>& operator>= (const T t, const matrix<T>& mx);
template<class T> matrix<bool>& operator== (const T t, const matrix<T>& mx);
template<class T> matrix<bool>& operator!= (const T t, const matrix<T>& mx);
As commented by #user2079303, the problem is due to my use of std::vector<bool>, not related to template c++. vector<bool> does not provide a pointer to its data. I change from using bool to char or int so that my program is nicely compiled. Thank you #user2079303.

Overloading of operators with class instance as right-hand side

I'm trying to do overload to * operator in my Matrix class.
I have one that make it if it is Matrix*something, (int, double...)
i'm searching for one that make it for the opposite side i.e something*Matrix
this is what i tried
template<class T>
bool operator*(Matrix<T>& other ){
Matrix<T> mat(other.rows,other.columns);
for(int i=0;i<other.rows;i++){
for(int j=0;j<other.columns;j++){
T temp=other.get(i,j);
temp=temp*(this);
mat.set(i,j,temp);
}
}
return mat;
}
and this is what works for Matrix*something
Matrix<T>& operator*(const T & num){
Matrix<T> mat(rows,columns);
for(int i=0;i<rows;i++){
for(int j=0;j<columns;j++){
T temp=(matrix[i][j]);
temp=temp*num;
mat.set(i,j,temp);
}
}
return mat;
}
You should make it a non-member, that is you write outside of Matrix class:
template<class T>
Matrix<T> operator*(const T& num, const Matrix<T>& mat) {
return mat * num; // invoke existing implementation of Matrix * something
}
Note that operator* should return result by value. There is a bug in your implementation, you return dangling reference to a local variable mat.
Note that this form requires num to be of type T so if, like in your example, you have
Matrix<Rational> mat;
mat = 3 * mat;
it won't compile because 3 is not Rational.
What you can do is use identity trick to put num parameter in non-deduced context, so it will be converted from int to Rational:
template<class T>
Matrix<T> operator*(typename boost::mpl::identity<T>::type const& num, const Matrix<T>& mat) {
return mat * num; // invoke existing implementation of Matrix * something
}
Where identity is just
template<typename T>
struct identity { typedef T type; };
Or you can do just
template<class T, class U>
Matrix<T> operator*(const U& num, const Matrix<T>& mat) {
return mat * num; // invoke existing implementation of Matrix * something
}

Cannot convert from *const to & in += operator [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I was staring at this all night before I decided to give up and go to sleep - a few hours into it again today, I still don't have it. I am unable to figure out how to change the const-ness and parameters to correctly return (on the operator+=). Any help?
The error pops up at the return this statement in the operator+= overload.
#include <iostream>
#include <vector>
template <typename T> class Matrix {
private:
unsigned rows, cols;
public:
Matrix();
~Matrix();
Matrix(const Matrix<T>& rhs);
Matrix(unsigned _rows, unsigned _cols);
std::vector<std::vector<T>> matrix;
Matrix<T>& operator=(Matrix<T> rhs);
//Matrix mathematical operations
Matrix<T> operator+(const Matrix<T>& rhs);
Matrix<T>& operator+=(const Matrix<T>& rhs);
// Access the individual elements
T& operator()(const unsigned& row, const unsigned& col);
const T& operator()(const unsigned& row, const unsigned& col) const;
// Access the row and column sizes
unsigned get_rows() const;
unsigned get_cols() const;
void swap(Matrix<T>& rhs);
};
template<typename T>
Matrix<T>::Matrix() {}
template<typename T>
Matrix<T>::~Matrix() {}
// Parameter Constructor
template<typename T>
Matrix<T>::Matrix(unsigned _rows, unsigned _cols) {
matrix.resize(_rows);
for (unsigned i = 0; i < _rows; i++)
matrix[i].resize(_cols, 1); // change back to 0 after debug
rows = _rows;
cols = _cols;
}
template<typename T>
Matrix<T>& Matrix<T>::operator=(Matrix<T> rhs) {
swap(rhs);
return *this;
}
template<typename T>
Matrix<T> Matrix<T>::operator+(const Matrix<T>& rhs) {
Matrix<T> result(*this);
result += rhs;
return result;
}
template<typename T>
Matrix<T>& Matrix<T>::operator+=(const Matrix<T>& rhs) {
for (unsigned i = 0; i < rows; i++) {
for (unsigned j = 0; j < cols; j++) {
this->matrix[i][j] += rhs(i, j);
}
}
return this; // error pops up here
}
// Access the individual elements
template<typename T>
T& Matrix<T>::operator()(const unsigned& row, const unsigned& col) {
return this->matrix[row][col];
}
// Access the individual elements (const)
template<typename T>
const T& Matrix<T>::operator()(const unsigned& row, const unsigned& col) const{
return this->matrix[row][col];
}
// Get the number of rows of the matrix
template<typename T>
unsigned Matrix<T>::get_rows() const {
return this->rows;
}
//Get the number of columns of the matrix
template<typename T>
unsigned Matrix<T>::get_cols() const {
return this->cols;
}
template<typename T>
void Matrix<T>::swap(Matrix<T>& rhs) {
using std::swap;
swap(this->rows, rhs.rows);
swap(this->cols, rhs.cols);
swap(this->matrix, rhs.matrix);
}
// for debugging
template<typename T>
void print_matrix(Matrix<T>& matrix) {
for (int i = 0; i < matrix.get_rows(); i++) {
for (int j = 0; j < matrix.get_cols(); j++) {
std::cout << matrix(i, j) << " ";
}
std::cout << " " << std::endl;
}
}
int main(int argc, char **argv) {
Matrix<double> matrix1(5, 5);
Matrix<double> matrix2(5, 5);
// Start testing
Matrix<double> matrix3 = matrix1 + matrix2;
print_matrix(matrix1);
std::getchar();
return 0;
}
In the += operator, you probably want:
Matrix<T>& Matrix<T>::operator+=(const Matrix<T>& rhs) {
//....
return *this;
//^^
}
The linker error is because you did not define:
Matrix(const Matrix<T>& rhs);