I have a template of a matrix class:
template <typename T>
class Matrix {
And many functions (like adding two matrices) return std::optional. I wanted to make an operator that would unwrap the value (or throw an exception):
template <class T>
Matrix<T> operator!(const std::optional<Matrix<T>>& other) {
return other.value();
}
Doing that I get the error C2440: "Cannot convert from const _Ty to Matrix< int > with [ _Ty = Matrix]". It says that construction of Matrix class cannot be done because of ambiguous copying constructors or unavailable copying constructor.
EDIT:
#include <iostream>
#include <optional>
template <typename T>
class Matrix {
private:
T** matrix;
int sizeX;
int sizeY;
public:
Matrix(int x, int y);
Matrix(Matrix<T>& other);
Matrix(Matrix<T>&& other);
void set_value(T val, int x, int y);
std::optional<Matrix<T>> vec_from_col(int colIndex);
};
template <typename T>
Matrix<T>::Matrix(int x, int y) {
std::cout << "Matrix Param\n";
if (x <= 0 || y <= 0) {
return;
throw -1;
}
else {
matrix = new T*[x];
for (int i = 0; i < x; i++) {
matrix[i] = new T[y];
for (int j = 0; j < y; j++) {
matrix[i][j] = 0;
}
}
sizeX = x;
sizeY = y;
}
}
template <typename T>
Matrix<T>::Matrix(Matrix<T>& other) {
std::cout << "Matrix Copy\n";
sizeX = other.sizeX;
sizeY = other.sizeY;
matrix = new T*[sizeX];
for (int i = 0; i < sizeX; i++) {
matrix[i] = new T[sizeY];
for (int j = 0; j < sizeY; j++) {
matrix[i][j] = other.matrix[i][j];
}
}
}
template <typename T>
Matrix<T>::Matrix(Matrix<T>&& other) {
std::cout << "Matrix Move\n";
sizeX = other.sizeX;
sizeY = other.sizeY;
matrix = other.matrix;
other.matrix = NULL;
}
template <typename T>
void Matrix<T>::set_value(T val, int x, int y) {
if (x < 0 || x >= sizeX || y < 0 || y >= sizeY) {
std::cout << "Invalid index was given. Matrix was unchanged.\n";
return;
}
else {
matrix[x][y] = val;
}
}
template <typename T>
std::optional<Matrix<T>> Matrix<T>::vec_from_col(int colIndex) {
if (colIndex < 0 || colIndex >= sizeX) {
return {};
}
Matrix<T> newVec(1, sizeY);
for (int i = 0; i < sizeY; i++) {
newVec.set_value(matrix[colIndex][i], 0, i);
}
return newVec;
}
template <class T>
Matrix<T> operator!(const std::optional<Matrix<T>>& other) {
return other.value();
}
int main() {
Matrix<int> test(2, 3);
test.set_value(10, 0, 1);
test.set_value(5, 0, 0);
test.set_value(13, 0, 2);
test.set_value(8, 1, 0);
Matrix<int> vec = !test.vec_from_col(0);
}
Your copy constructor is wrong which causes this ambiguity.
Matrix(Matrix<T>& other);
should be
Matrix(const Matrix<T>& other);
Note: You also leak memory since you new[] but don't delete[].
Related
I wrote the following code for creating a chessboard using 2D Arrays in C++ :
#include <iostream>
#include <iomanip>
#include <array>
using namespace std;
Here is the ChessBoardArray class:
class ChessBoardArray
{
protected:
class Row
{
public:
Row(ChessBoardArray &a, int i): cba(a), row(i){}
int & operator[] (int i) const
{
return cba.select(row, i);
}
private:
ChessBoardArray &cba;
int row;
};
class ConstRow
{
public:
ConstRow(const ChessBoardArray &a, int i): cba(a), row(i){}
int operator[] (int i) const
{
return cba.select(row, i);
}
private:
const ChessBoardArray &cba;
int row;
};
unsigned int my_size;
int my_base;
int *data;
The loc function is for finding the location of an element. It corresponds the elements of the 2D array to the corresponding position.
unsigned int loc(int i, int j) const throw(out_of_range)
{
int di = i - my_base, dj = j - my_base;
if(di < 0 || di >= my_size || dj < 0 || dj >= my_size) throw out_of_range("invalid index");
return di * my_size + dj;
}
public:
ChessBoardArray(unsigned size = 0, unsigned base = 0)
{
my_size = size;
my_base = base;
data = new int[my_size * my_size];
}
ChessBoardArray(const ChessBoardArray &a)
{
my_size = a.my_size;
my_base = a.my_base;
data = new int[my_size * my_size];
for(int i = 0; i < my_size*my_size; i++) data[i] = a.data[i];
}
~ChessBoardArray()
{
delete [] data;
}
ChessBoardArray & operator= (const ChessBoardArray &a)
{
this -> ~ChessBoardArray();
my_size = a.my_size;
my_base = a.my_base;
data = new int[my_size * my_size];
for(int i = 0; i < my_size*my_size; i++) data[i] = a.data[i];
return *this;
}
int & select(int i, int j)
{
return data[loc(i, j)];
}
int select(int i, int j) const
{
return data[loc(i, j)];
}
const Row operator[] (int i)
{
return Row(*this, i);
}
const ConstRow operator[] (int i) const
{
return ConstRow(*this, i);
}
friend ostream& operator<< (ostream &out, const ChessBoardArray &a)
{
for(int i = a.my_base; i <= a.my_size; i++)
{
for(int j = a.my_base; j <= a.my_size; j++)
{
out << setw(4) << a.data[a.loc(i, j)];
}
out << endl;
}
return out;
}
};
The condition for a number to be in a white box is i%2 == j%2. Where should i add the condition in my code?
I tried putting it inside the loc function but it got me some errors.
I have written a c++ program to check whether a matrix is sparse or not. The syntax errors which come up are as follows:
main.cpp:56:8: error: deduced class type ‘matrix’ in function return type
matrix matrix <T>::add(matrix r)
^~~~~~~~~~
main.cpp:11:7: note: ‘template class matrix’ declared here
class matrix
^~~~~~
main.cpp:56:8: error: prototype for ‘matrix matrix::add(matrix)’ does not match any in class ‘matrix’
matrix matrix <T>::add(matrix r)
^~~~~~~~~~
main.cpp:19:9: error: candidate is: matrix matrix::add(matrix&)
matrix add(matrix&);
^~~*
And the program is:
#include<iostream>
#include <exception>
using namespace std;
class mismatchDimension:public exception
{
public:
void error_Msg () const;
};
template < class T >
class matrix
{
int row;
int col;
T ele[10][10];
public:
void get ();
bool check_Sparse ();
matrix add (matrix &);
void print ();
};
//no changes to be made to the above code
void mismatchDimension::error_Msg () const const //Error printing method
{
cout << "Dimension of matrices do not match" << endl;
}
template < class T >
void matrix < T >::get () //Element input of matrix
{
cin >> row;
cin >> col;
int i, j;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
cin >> ele[j][i];
}
}
template < class T >
bool matrix < T >::check_Sparse () //Check if the matrix is sparse
{
int i, j, t;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if (ele[j][i] == 0) ++t;
}
}
if (t > (row * col) / 2) return true;
else return false;
}
template < class T >
matrix matrix < T >::add (matrix r) //Addition of the matrices
{
mismatchDimension z;
int i, j;
matrix < T > w;
if (row != r.row && col != r.col) throw z;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
w.ele[j][i] = ele[j][i] + r.ele[j][i];
}
}
return w;
}
template < class T >
void matrix < T >::print () //printing the matrix
{
int i, j;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++) cout << ele[j][i] << endl;
}
}
// no changes to be made below
int
main ()
{
matrix < int >m1, m2, m3;
m1.get ();
m2.get ();
try
{
m3 = m1.add (m2);
m3.print ();
} catch (mismatchDimension & m)
{
m.error_Msg ();
}
if (m1.check_Sparse ())
cout << "Matrix is sparse" << endl;
else
cout << "Matrix is not sparse" << endl;
}
There are multiple issues:
In the declaration matrix add (matrix &); you pass by reference while in the definition matrix matrix < T >::add (matrix r) you pass by value. Choose only one.
The return type specification and the parameter type should be provided with template argument:
template <class T>
matrix<T> matrix<T>::add (matrix r)
{
...
}
Note that since C++11, you can also omit template argument in the return type with trailing return type declaration:
template <class T>
auto matrix<T>::add (matrix r) -> matrix
{
...
}
The method template <class T> const Matrix<T> Matrix<T>::operator+(const Matrix<T> &rhs) const for program matrix.cc should be able to return the sum of calling object's matrix and rhs's matrix as a new object. Also, the lhs and rhs rows and cols will be equal.
The error output that I am receiving from the compiler is:
[hw7] make clean && make bin/test_add && ./bin/test_add UserSettings ✱
rm -f bin/*
g++ -std=c++11 -Wall -I inc -I src -c src/test_matrix_add.cc -o bin/test_matrix_add.o
g++ -std=c++11 -Wall -I inc -I src -o bin/test_add bin/test_matrix_add.o
Testing Matrix::operator+
Expected Matrix2[0][0]: 3.0, Actual: 1
FAILED
Could someone let me know why I receive this "Failed" output when I know I pass the // TEST MUL ASSIGMENT OP CORRECT RETURN section.
Here is my matrix.cc:
#include <matrix.h>
template <class T>
Matrix<T>::Matrix() {
rows_ = 0;
cols_ = 0;
m_ = nullptr;
}
template <class T>
Matrix<T>::Matrix(unsigned int rows, unsigned int cols)
: rows_(rows), cols_(cols) {
m_ = new T *[rows_];
for (unsigned int i = 0; i < rows_; ++i) {
m_[i] = new T[cols_];
}
}
template <class T>
Matrix<T>::Matrix(const Matrix<T> &that) {
rows_ = that.rows_;
cols_ = that.cols_;
m_ = new T *[rows_];
for (unsigned int i = 0; i < rows_; ++i) {
m_[i] = new T[cols_];
for (unsigned int j = 0; j < cols_; ++j) {
m_[i][j] = that.m_[i][j];
}
}
}
template <class T>
Matrix<T>::~Matrix() {
for (unsigned int i = 0; i < rows_; ++i) {
delete[] m_[i]; // delete columns
}
delete[] m_; // delete columns
}
template <class T>
T Matrix<T>::Get(unsigned int row, unsigned int col) const {
if (row > rows_ && col > cols_) {
throw std::out_of_range("error: index out of range");
}
return this->m_[row][col];
}
template <class T>
const Matrix<T> &Matrix<T>::operator=(const Matrix<T> &rhs) {
if (this == &rhs) {
return *this;
} // returns the address
for (unsigned int i = 0; i < rows_; ++i) {
delete[] m_[i];
}
delete[] m_;
rows_ = rhs.rows_;
cols_ = rhs.cols_;
m_ = new T *[rows_];
for (unsigned int i = 0; i < rows_; ++i) {
m_[i] = new T[cols_];
for (unsigned int j = 0; j < cols_; ++j) {
m_[i][j] = rhs.m_[i][j];
}
}
return *this;
}
template <class T>
const Matrix<T> &Matrix<T>::operator*=(T rhs) {
for (unsigned int i = 0; i < rows_; ++i) {
for (unsigned int j = 0; j < cols_; ++j) {
m_[i][j] *= rhs;
}
}
return *this;
}
template <class T>
const Matrix<T> Matrix<T>::operator+(const Matrix<T> &rhs) const {
if (!(this->cols_ == rhs.cols_) || (this->rows_ == rhs.rows_)) {
std::cout << "Cannont add matrices. Wrong dimensions\n";
exit(0);
}
Matrix<T> lhs;
lhs.rows_ = this->rows_;
lhs.cols_ = this->cols_;
for (unsigned int i = 0; i < lhs.rows_; ++i) {
for (unsigned int j = 0; j < lhs.cols_; ++j) {
lhs[i][j] += rhs[i][j];
}
}
return lhs;
}
Here is my matrix.h:
#include <cassert>
// using assert
#include <exception>
#include <iostream>
template <class T>
class Matrix {
public:
friend class MatrixTester;
Matrix(); // for testing, useless in practice
Matrix(unsigned int rows, unsigned int cols);
Matrix(const Matrix<T> &that);
~Matrix();
T Get(unsigned int row, unsigned int col) const;
const Matrix<T> &operator=(const Matrix<T> &rhs);
const Matrix<T> &operator*=(T rhs);
const Matrix<T> operator+(const Matrix<T> &rhs) const;
private:
T **m_;
unsigned int rows_;
unsigned int cols_;
};
#include <matrix.cc> //NOLINT
This is my test_matrix_add.cc tester:
#include <test_matrix.h>
int main(int argc, char** argv) {
MatrixTester tester;
cout << "Testing Matrix::operator+" << endl;
if (tester.Test_AddOp()) {
cout << " PASSED" << endl;
return 0;
}
cout << " FAILED" << endl;
return 1;
}
bool MatrixTester::Test_AddOp() const {
const int kRows = 4, kCols = 5;
Matrix<double> m1;
m1.m_ = new double*[kRows];
for (unsigned int i = 0; i < kRows; ++i) {
m1.m_[i] = new double[kCols];
for (unsigned int j = 0; j < kCols; ++j)
m1.m_[i][j] = (i + 1.0) * (j + 1.0);
}
m1.rows_ = kRows;
m1.cols_ = kCols;
// TEST ADDITION CORRECTNESS
Matrix<double> m2;
m2 = m1;
// + m1 + m1;
if (m2.m_[0][0] != 3) {
cout << " Expected Matrix2[0][0]: 3.0, Actual: " << m2.m_[0][0] << endl;
return false;
}
if (m2.m_[1][3] != 24.0) {
cout << " Expected Matrix2[1][3]: 24.0, Actual: " << m2.m_[1][3] << endl;
return false;
}
if (m2.m_[2][2] != 27.0) {
cout << " Expected Matrix2[2][2]: 27.0, Actual: " << m2.m_[2][2] << endl;
return false;
}
if (m2.m_[3][4] != 60.0) {
cout << " Expected Matrix2[2][2]: 60.0, Actual: " << m2.m_[2][2] << endl;
return false;
}
return true;
}
Firstly, there is way too much code here.
To address your problem, I see don't see you allocating memory to lhs.m_. This is a problem because you initialize lhs with the default constructor, which only assigns this->m_ to a nullptr.
To fix this, this should work (although untested):
template <class T>
const Matrix<T> Matrix<T>::operator+(const Matrix<T>& rhs) const
{
if (!(this->cols_ == rhs.cols_) || (this->rows_ == rhs.rows_))
{
std::cout << "Cannot add matrices. Wrong dimensions\n";
exit(0);
}
Matrix<T> lhs;
lhs.rows_ = this->rows_;
lhs.cols_ = this->cols_;
// Allocate memory for `lhs.m_`, like you did in your 2nd constructor
lhs.m_ = new T* [rows_];
for (unsigned i = 0; i < rows_; ++i)
{
m_[i] = new T[cols_];
}
// [End] allocation
for (unsigned int i = 0; i < lhs.rows_; ++i)
{
for (unsigned int j = 0; j < lhs.cols_; ++j)
{
lhs[i][j] += rhs[i][j];
}
}
return lhs;
}
Also, somewhat unrelated, be careful that you consistently treat m_ as a double-pointer. I didn't read all your code, but just be cautious. And also remember that you have to deallocate all the memory you allocated with new in your destructor. Personally, I believe you should use smart pointers from <memory> (e.g. std::unique_ptr, etc), which you can learn more about here. Using smart pointers would make the pointers deallocate the memory on their own and you wouldn't have to worry about memory leaks.
Edit 1
As walnut stated, a better solution would be to just call the 2nd constructor, which will allocate the memory for you. So, your revised function would be:
template <class T>
/**
Note:
> When you call this function (e.g. Matrix<T> new_mat = mat1 + mat2),
`mat1` is `this` and `mat2` is what you're calling `rhs`. I've done
some renaming and corrected your logic errors here
*/
const Matrix<T> Matrix<T>::operator+(const Matrix<T>& other) const
{
if (!(this->cols_ == other.cols_) || (this->rows_ == other.rows_))
{
std::cout << "Cannot add matrices. Wrong dimensions\n";
exit(0);
}
// Call the 2nd constructor
Matrix<T> res(this->rows_, this->cols_);
for (unsigned i = 0; i < res.rows_; ++i)
{
for (unsigned j = 0; j < res.cols_; ++j)
{
res.m_[i][j] = this->m_[i][j] + other.m_[i][j];
}
}
return res;
}
Edit 2
The above code has been correct to add the matrices correctly, as per #walnut's comment.
There are two files:
Matrix.hpp:
template <typename T>
class Matrix {
private:
size_t rows = 0;
size_t cols = 0;
T* data = nullptr;
public:
Matrix() = default;
~Matrix();
Matrix(size_t n, size_t m);
T& operator() (size_t i, size_t j);
};
template <typename T>
Matrix<T>::Matrix(size_t n, size_t m) : rows(n), cols(m) {
try {
data = new T[rows*cols];
} catch (const std::bad_alloc& e) {
std::exit(EXIT_FAILURE);
}
};
template <typename T>
Matrix<T>::~Matrix() {
delete[] data;
}
template <typename T>
T& Matrix<T>::operator()(size_t i, size_t j) {
if (i < rows && i >= 0 && j < cols && j >= 0) {
return data[(i+1)*cols + (j+1)];
} else {
throw std::logic_error("matrix indices out of range");
}
}
and
Main.cpp:
#include <iostream>
#include "Matrix.hpp"
int main() {
size_t n, k;
std::cin >> n >> k;
Matrix<long double> m = {n, k};
for (size_t i = 0; i < m.getNumRows(); ++i) {
for (size_t j = 0; j < m.getNumCols(); ++j) {
std::cin >> m(i,j);
}
}
for (size_t i = 0; i < m.getNumRows(); ++i) {
std::cout << "\n";
for (size_t j = 0; j < m.getNumCols(); ++j) {
std::cout << m(i, j) << " ";
}
}
return 0;
}
When I'm entering something like:
1 2 3 4
I can get
3 4
as answer but sometimes the same input causes Segmentation fault 11 moreover when I'm changing template argument from long double to int, error disappears. How can I fix it?
Your operator function is accessing data outside its bounds.
Passing (0,0) to the function should return data[0]. Currently it returns data[2].
Change line
return data[(i+1)*cols+(j+1)];
to
return data[i*cols+j];
I am not sure if I am correctly overloading the << operator. The following code compiles without problem but does not produce the expected output.
#include <iostream>
#include "Matrix.h"
template<class T>
std::ostream& operator<<(std::ostream &out, const matrix<T> &A)
{
for(int ii = 0; ii << A.size(1); ii++)
{
for(int jj = 0; jj < A.size(2); jj++)
{
out << A(ii,jj) << " ";
}
out << std::endl;
}
return out;
}
int main(int argc, char** argv)
{
matrix<double> A = {{1.0, 2.0},{1.0,-1.0}};
cout << "\"" << A << "\"\n";
return 0;
}
The only output is:
""
Matrix.h
template<class T>
class matrix
{
public:
matrix(int rows, int cols);
matrix(const std::initializer_list<std::initializer_list<T>>& lst);
T& operator()(int i, int j);
T operator()(int i, int j) const;
int size(int n) const;
private:
int mRows;
int mCols;
std::vector<T> mData;
};
template<class T>
matrix<T>::matrix(int rows, int cols)
: mRows(rows),
mCols(cols),
mData(rows * cols)
{
}
template<class T>
matrix<T>::matrix(const std::initializer_list<std::initializer_list<T> >& lst)
: matrix(lst.size(), lst.size() ? lst.begin()->size() : 0)
{
int ii = 0, jj = 0;
for(const auto& l : lst)
{
for(const auto& v : l)
{
mData[ii*mCols + jj] = v;
jj++;
}
jj = 0;
ii++;
}
}
template<class T>
T& matrix<T>::operator()(int i, int j)
{
return mData[i*mCols + j];
}
template<class T>
T matrix<T>::operator()(int i, int j) const
{
return mData[i*mCols + j];
}
template<class T>
int matrix<T>::size(int n) const
{
if(n == 1)
{
return mRows;
}
else if(n == 2)
{
return mCols;
}
}
In your first for loop, you have:
for(int ii = 0; ii << A.size(1); ii++)
^
That should be a single < character:
for(int ii = 0; ii < A.size(1); ii++)
^
The reason why it wasn't doing anything is because the original loop resulted in a condition of 0 << A.size(1), which is 0, or false; thus, the outer loop is never executed.