Overload assign after overloading [][] - c++

What begun as a revision of some aspects of C++ has become a sketch of something that could be useful for me. The idea is to use a single array as a double array where indexing is transparent for the user.
class matrice {
private:
int* data;
int rows, cols;
public:
matrice(int _rows, int _cols) : rows(_rows), cols(_cols) { data = new int[_rows*_cols]; std::cout << "matrice ctr" << std::endl;}
// hardcoded 2x2 matrix
void set_value() { data[0] = 1; data[1] = 0; data[3] = 1; data[4] = 0;}
int get_rows() { return rows;}
int get_cols() { return cols;}
class proxy {
private:
int i;
int j;
const int rows; // it is constant so we don't mess up with the size of the matrix
int *proxy_data;
public:
proxy(int* _proxy_data, int _i, const int& _rows) : proxy_data(_proxy_data), i(_i), rows(_rows) { }
int operator[] (int _j) { j = _j; std::cout << "proxy:\n\tj = " << j << " " << proxy_data[j] << std::endl; return proxy_data[i*rows + j];}
};
proxy operator[] (int i) { std::cout << "matrice:\n\ti = " << i << std::endl; return proxy(data, i, rows); }
};
int main()
{
int rows = 2;
int cols = 2;
matrice matp(rows, cols);
matp.set_value();
matp[0][0] = 2;
for (int i = 0;i < rows;i++) {
for (int j = 0;j < cols;j++) {
std::cout << "matp[" << i << "][" << j << "] = " << matp[i][j] << std::endl;
}
}
}
So far I can access the data in the array however, I want to assign values to it i.e.:
matp[0][0] = 2;
How could I do it ?

int& operator[] (int j)const&&
Also delets int j member it is pointless.
int& operator[] (int j) const&& {
std::cout << "proxy:\n\tj = " << j << " " << proxy_data[j] << std::endl;
return proxy_data[i*rows + j];}
};
or better:
template<class X>
class proxy {
private:
X *proxy_data;
public:
proxy(X* _proxy_data, std::size_t i, std::size_t stride) : proxy_data(_proxy_data+i*stride) { }
X& operator[] (std::size_t j) const&& { return proxy_data[j]; }
};
use proxy<int> and proxy<const int> as the return value from [] and [] const.

Related

Error in implementation of Matrix multiplication using template classes

I got a homework which looks something like this. I am working on it and hold beginner knowledge of the same.
I have to create a header file that contains this code and then use the header file to get the desired results.
I am working with C++ template, and operator overloading.
#include <iostream>
#include <memory>
#include "matrix.h"
#include "symetric_matrix.h"
using namespace std;
int main()
{
const Matrix<int, 3, 2> m1; // Creates 3*2 matrix, with all the default elements set to 0;
cout << m1 << endl;
Matrix<int, 3, 3> m2(4); // Creates 3*3 matrix, with the default elements equals to 4;
cout << m2 << endl;
const Matrix<int, 3, 3> m3 = m2; // C-py constructor may take O(MN) and not O(1).
cout << m3 << endl;
// min() returns the minimal value in the matrix.
if (min(m1) < min(m3))
cout << "Min value of m3(" << min(m3) << ") is bigger than min value of m1(" << min(m1) << ")" << endl;
if (m1.avg() < m3.avg()) // Compares the average of the elements
cout << "Average value of m3(" << m3.avg() << ") is bigger than average value of m1(" << m1.avg() << ")" << endl;
m2(0, 0) = 13;
cout << m2[0][0] << " " << m2[1][0] << endl; // Should print "13 4"
try
{
cout << m2 + m3 << endl;
cout << m3 * m1 << endl; // You can choose the format of matrix printing;
cout << m1 * m2; // This should throw an exception
}
catch (const Matrix<int, 3, 2>::IllegalOperation &e)
{
cout << e.what() << endl;
}
Matrix<int, 3, 3> m4;
m4 = m3;
cout << m4 << endl;
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 3; ++j)
m4(i, j) = i + j;
cout << m4 << endl;
cout << "m4[1][1] = " << m4[1][1] << endl;
cout << "m4[1][1] = " << m4(1, 1) << endl; // m4(1,1) same result as m4[1][1]
Matrix<int, 3, 3> m5(3);
m5 = 2 * m4;
cout << m5 << endl;
Matrix<int, 3, 3> m6(m4);
cout << m6 << endl;
m5 += m4;
cout << m5 << endl;
if (m6 != m5)
cout << "m6 != m5" << endl;
Matrix<Matrix<int, 3, 2>, 4, 4> composite(m1); // Creates matrix, where each element is m1;
cout << composite;
unique_ptr<Matrix<int, 3, 3>> symetric_matrix(new SymetricMatrix<int, 3>(5)); // SymetricMatrix matrix 3*3 with default element equals to 5;
(*symetric_matrix)(1, 2) = 8;
cout << (*symetric_matrix)(1, 2) << " " << (*symetric_matrix)(2, 1) << endl; // Should print "8 8"
cout << (*symetric_matrix)[1][2] << " " << (*symetric_matrix)[2][1] << endl; // Should print "8 8"
(*symetric_matrix)[1][0] = 18;
cout << (*symetric_matrix)[1][0] << " " << (*symetric_matrix)[0][1] << endl; // Should print "18 18"
return 0;
}
My Updated solution for now.
template <class T, int M, int N>
class Matrix
{
private:
T mat[M][N];
int rows = M;
int cols = N;
public:
// constructor
Matrix(int v = 0)
{
for (int i = 0; i < M; i++)
{
for (int j = 0; j < N; j++)
mat[i][j] = v;
}
}
T &operator()(int i, int j)
{
return mat[i][j];
};
T *operator[](int index)
{
return mat[index];
};
// << overloading
friend std::ostream &operator<<(std::ostream &os, const Matrix<T, M, N> &L)
{
for (int i = 0; i < M; i++)
{
for (int j = 0; j < N; j++)
os << L.mat[i][j] << " ";
os << "\n";
}
return os;
};
template <class T1, int M1, int N1>
Matrix<T, M, M> operator*(Matrix<T1, M1, N1> const &other);
Matrix<T, M, M> operator+(Matrix<T, M, N> const &other);
friend T min(Matrix obj)
{
T result = obj.mat[0][0];
for (int i = 0; i < M; i++)
{
for (int j = 0; j < N; j++)
if (result < obj.mat[i][j])
result = obj.mat[i][j];
}
return result;
};
long double avg() const
{
long double result = 0;
for (int i = 0; i < M; i++)
{
for (int j = 0; j < N; j++)
if (result < mat[i][j])
result = result + mat[i][j];
}
return result / (M * N);
}
};
template <class T, int M, int N>
Matrix<T, M, M> Matrix<T, M, N>::operator+(Matrix const &other)
{
if ((this->rows == other.rows) && (this->cols == other.cols))
{
Matrix<T, M, N> resultantMatrix;
for (auto i = 0; i < this->rows; i++)
{
for (auto j = 0; j < this->cols; j++)
{
auto &valueFirst = this->mat[i][j];
auto &valueSecond = other.mat[i][j];
// if ((additionOverflow(valueFirst, valueSecond)) || (additionUnderflow(valueFirst, valueSecond)))
// throw std::out_of_range("Resultant value of matrix is out of range");
// else
resultantMatrix(i, j) = valueFirst + valueSecond;
}
}
return resultantMatrix;
}
else
throw std::runtime_error("Matrices cannot be added, sizes do not match");
}
template <class T, int M, int N>
template <class T1, int M1, int N1>
Matrix<T, M, M> Matrix<T, M, N>::operator*(Matrix<T1, M1, N1> const &other)
{
if ((this->rows == other.rows) && (this->cols == other.cols))
{
Matrix<T, M, N> resultantMatrix;
for (auto i = 0; i < this->rows; i++)
{
for (auto j = 0; j < this->cols; j++)
{
for (auto k = 0; k < this->cols; k++)
{
auto &valueFirst = this->mat[i][k];
auto &valueSecond = other(k, j);
// if ((additionOverflow(valueFirst, valueSecond)) || (additionUnderflow(valueFirst, valueSecond)))
// throw std::out_of_range("Resultant value of matrix is out of range");
// else
resultantMatrix(i, j) += valueFirst * valueSecond;
}
}
}
return resultantMatrix;
}
else
throw std::runtime_error("Matrices cannot be added, sizes do not match");
}
I am getting an error and I don't understand why.
error: no match for call to ‘(const Matrix<int, 3, 2>) (int&, int&)’
112 | auto &valueSecond = other(k, j);
| ~~~~~^~~~~~
matrix.h:20:8: note: candidate: ‘T& Matrix<T, M, N>::operator()(int, int) [with T = int; int M = 3; int N = 2]’ (near match)
20 | T &operator()(int i, int j)
| ^~~~~~~~
matrix.h:20:8: note: passing ‘const Matrix<int, 3, 2>*’ as ‘this’ argument discards qualifiers
It only happens at this line auto &valueSecond = other(k, j); and not this one resultantMatrix(i, j) += valueFirst * valueSecond;, Why?
I just need help with the whole program while I try and learn!
Any help is appreciated.
As for the error message
matrix.h:20:8: note: passing ‘const Matrix<int, 3, 2>*’ as ‘this’ argument discards qualifiers
other is const Matrix<int, 3, 2>&. The T &operator()(int i, int j) is implemented for non const Matrix<int, 3, 2>&. There should be provided two versions of the operators
T &operator()(int i, int j)
{
return mat[i][j];
};
const T &operator()(int i, int j) const
{
return mat[i][j];
};
T *operator[](int index)
{
return mat[index];
};
const T *operator[](int index) const
{
return mat[index];
};
Using operator() as a subscript operator may be confusing. It should be
T &operator[](int i, int j)
{
return mat[i][j];
};
const T &operator[](int i, int j) const
{
return mat[i][j];
};
Subscript operators usually are defined for size_t types.

'this' cannot be used in a constant expression error

The error is on line 76 int res[mSize]; the problem is on mSize. It seems like a simple fix but I can't figure it out. If someone can figure it out or point me in the right direction that would be greatly appreciated.
Also, the deconstructor ~MyContainer(), I am not sure if I am using it right or if there is a correct place to put it.
Here is my code:
#include <iostream>
using namespace std;
class MyContainer
{
private:
int* mHead; // head of the member array
int mSize; // size of the member array
public:
MyContainer();
MyContainer(int*, int);
//~MyContainer();
void Add(int);
void Delete(int);
int GetSize();
void DisplayAll();
int FindMissing();
~MyContainer() {}
};
MyContainer::MyContainer()
{
mHead = NULL;
mSize = 0;
}
MyContainer::MyContainer(int* a, int b)
{
mHead = a;
mSize = b;
}
void MyContainer::Add(int a)
{
*(mHead + mSize) = a;
mSize++;
}
void MyContainer::Delete(int a)
{
int index;
for (int i = 0; i < mSize; i++)
{
if (*(mHead + i) == a)
{
index = i;
break;
}
}
for (int i = index; i < mSize; i++)
{
*(mHead + i) = *(mHead + i + 1);
}
mSize--;
}
int MyContainer::GetSize()
{
return mSize;
}
void MyContainer::DisplayAll()
{
cout << "\n";
for (int i = 0; i < mSize; i++)
{
cout << *(mHead + i) << " ";
}
}
int MyContainer::FindMissing()
{
int res[mSize];
int temp;
int flag = 0;
for (int i = 1; i <= mSize; i++)
{
flag = 0;
for (int j = 0; j < mSize; j++)
{
if (*(mHead + j) == i)
{
flag = 1;
break;
}
}
if (flag == 0)
{
temp = i;
break;
}
}
return temp;
}
int main()
{
const int cSize = 5;
int lArray[cSize] = { 2, 3, 7, 6, 8 };
MyContainer lContainer(lArray, cSize);
lContainer.DisplayAll();
lContainer.Delete(7);
lContainer.DisplayAll();
cout << "Size now is: " << lContainer.GetSize() << endl; lContainer.Add(-1);
lContainer.Add(-10);
lContainer.Add(15);
lContainer.DisplayAll();
cout << "Size now is: " << lContainer.GetSize() << endl;
cout << "First missing positive is: " << lContainer.FindMissing() << endl;
system("PAUSE"); return 0;
}
int res[mSize];
The size of the array mSize must be known at compile time. You cannot use a variable here. An option may be to define a macro with an largish value that will not exceeded.
static const int kLargeSize =100;
int res[kLargeSize];
Edited in response to the comments - const and constexpr are a better option than a macro.
Or even better, you can use std::vector - https://en.cppreference.com/w/cpp/container/vector

Function to get minimal value of array in template

I have this code in main:
Array<int> array1 = Array<int>(5);
array1.coutArray();
cout << "Minimal value: " << min(array1, 5);
And I need function to get minimal value of array. I Tried this function:
template<class Array>
Array min(const Array* data, int size) {
T result = data[0];
for (int i = 1; i < size; i++)
if (result > data[i])
result = data[i];
return result;
}
But for every variant from internet I have one error about types of first argument. How to properly write this function or it's calling?
Array class:
template <class T>
class Array {
protected:
int size;
T* DynamicArray;
public:
Array() {};
Array(size_t s) : size(s) {
DynamicArray = new T[size];
for (int i = 0; i < size; i++) {
cout << "Element " << i+1 << ": ";
cin >> DynamicArray[i];
}
}
void coutArray() {
for (int i = 0; i < size; i++) {
cout << DynamicArray[i] << " ";
}
}
~Array() {
delete[]DynamicArray;
}
};
template<class Array>
Array getMin(Array* arr, int size)
{
for (int i = 0; i < size; i++) {
cout << arr[i];
}
}
If you need this for your Array template, it would be best to provide begin and end for it:
template <class T>
class Array {
protected:
int size;
T* DynamicArray;
public:
....
using value_type = T;
const T* begin() const {
return DynamicArray;
}
const T* end() const {
return DynamicArray + size;
}
T* begin() {
return DynamicArray;
}
T* end() {
return DynamicArray + size;
}
};
Then you should be able use STL algorithms.
template<typename T>
T minimum(const T &tab)
{
return *std::minimum_element(std::begin(tab), std::end(tab));
}
Note that your array is poor version of std::vector.
The function getMin should be either a member function of the class or a friend function of the class to have access to protected data members of the class.
Here is a demonstrative program that shows how the function can be defined as a member function of the class. I also made some minor changes in the class definition.
#include <iostream>
template <class T>
class Array {
protected:
size_t size;
T* DynamicArray;
public:
Array() : size( 0 ), DynamicArray( nullptr ) {}
Array(size_t s) : size(s) {
DynamicArray = new T[size];
for ( size_t i = 0; i < size; i++) {
std::cout << "Element " << i+1 << ": ";
std::cin >> DynamicArray[i];
}
}
void coutArray() const {
for ( size_t i = 0; i < size; i++) {
std::cout << DynamicArray[i] << " ";
}
}
~Array() {
delete[]DynamicArray;
}
const T * getMin() const
{
T *min = DynamicArray;
for ( size_t i = 1; i < size; i++ )
{
if ( DynamicArray[i] < *min ) min = DynamicArray + i;
}
return min;
}
};
int main()
{
Array<int> a( 5 );
const int *min = a.getMin();
if ( min != nullptr ) std::cout << "The minimum is equal to " << *min << '\n';
return 0;
}
The program output might look for example the following way
Element 1: 2
Element 2: 3
Element 3: 1
Element 4: 4
Element 5: 5
The minimum is equal to 1
And below there is a demonstrative program when the function is defined as a non-template friend function of the class.
#include <iostream>
template <class T>
class Array {
protected:
size_t size;
T* DynamicArray;
public:
Array() : size( 0 ), DynamicArray( nullptr ) {}
Array(size_t s) : size(s) {
DynamicArray = new T[size];
for ( size_t i = 0; i < size; i++) {
std::cout << "Element " << i+1 << ": ";
std::cin >> DynamicArray[i];
}
}
void coutArray() const {
for ( size_t i = 0; i < size; i++) {
std::cout << DynamicArray[i] << " ";
}
}
~Array() {
delete[]DynamicArray;
}
friend const T * getMin( const Array &a )
{
T *min = a.DynamicArray;
for ( size_t i = 1; i < a.size; i++ )
{
if ( a.DynamicArray[i] < *min ) min = a.DynamicArray + i;
}
return min;
}
};
int main()
{
Array<int> a( 5 );
const int *min = getMin( a );
if ( min != nullptr ) std::cout << "The minimum is equal to " << *min << '\n';
return 0;
}

declaring a function with arrays

First of all, im a c++ noob! Ok with that being said, i need to declare a function that initializes a grid. The function takes an array of int as the input and needs to return an array of int. I have:
array<int> InitializeGrid (array<int>)
{
const int NB_ROWS = 10;
const int NB_COLUMN = 10;
const int WATER = 0;
int grid[NB_ROWS][NB_COLONN];
for (int i = 0; i < NB_ROWS; i++)
{
for (int j = 0; j < NB_COLONN; j++)
{
grid[i][j] = WATER;
cout << grid[i][j] << " ";
}
cout << endl;
}
return ??
}
You don't need to return anything if you pass the array by reference:
#include <array>
#include <iostream>
static const int NB_ROWS = 10;
static const int NB_COLUMN = 10;
static const int WATER = 0;
void InitializeGrid (std::array<std::array<int, NB_COLUMN>, NB_ROWS> &grid)
{
for (auto &row : grid)
{
for (auto &col : row)
{
col = WATER;
std::cout << col << " ";
}
std::cout << '\n';
}
}
int main()
{
std::array<std::array<int, NB_COLUMN>, NB_ROWS> grid;
InitializeGrid(grid);
}
btw, if your WATER is 0 it is sufficive to write
std::array<std::array<int, NB_COLUMN>, NB_ROWS> grid{};
to initialize all elements to zero.

Why can't I change objects in a vector?

I have a class TileGrid that holds an std::vector< std::vector<Tile> >. Accessing the Tile objects in the vector works, but I can't change their properties? For the sake of completion, here are all the relevant classes:
tilegrid.h
#include <vector>
#include "tile.h"
class TileGrid {
public:
TileGrid();
TileGrid(unsigned int rows, unsigned int cols);
virtual ~TileGrid();
unsigned int getRows() const { return rows_; };
unsigned int getCols() const { return cols_; };
Tile atIndex(unsigned int row, unsigned int col) const { return tiles_[row].at(col); };
private:
std::vector< std::vector<Tile> > tiles_;
unsigned int rows_;
unsigned int cols_;
};
tilegrid.cpp
#include "tilegrid.h"
TileGrid::TileGrid() : rows_(0), cols_(0) {
}
TileGrid::TileGrid(unsigned int rows, unsigned int cols) : rows_(rows), cols_(cols) {
tiles_.clear();
for (unsigned int y = 0; y < rows_; y++) {
std::vector<Tile> horizontalTiles;
for (unsigned int x = 0; x < cols_; x++) {
horizontalTiles.push_back(Tile());
}
tiles_.push_back(horizontalTiles);
}
}
TileGrid::~TileGrid() {
}
tile.h
class Tile {
public:
Tile();
virtual ~Tile();
bool isActive() const { return isActive_; };
void setActive(bool status) { isActive_ = status; };
private:
bool isActive_;
};
tile.cpp
#include "tile.h"
Tile::Tile() : isActive_(false) {
}
Tile::~Tile() {
}
main.cpp
#include "tilegrid.h"
#include <iostream>
int main() {
TileGrid tg(20, 20);
for (unsigned int i = 0; i < tg.getRows(); i++) {
for (unsigned int j = 0; j < tg.getCols(); j++) {
if (tg.atIndex(i, j).isActive()) {
std::cout << i << "," << j << " is active" << std::endl;
} else {
std::cout << i << "," << j << " is NOT active" << std::endl;
}
}
}
// This is all working. But when I for example use the setActive function, nothing changes:
tg.atIndex(1, 0).setActive(true);
// When I print it again, the values are still the ones that were set in the constructor
for (unsigned int i = 0; i < tg.getRows(); i++) {
for (unsigned int j = 0; j < tg.getCols(); j++) {
if (tg.atIndex(i, j).isActive()) {
std::cout << i << "," << j << " is active" << std::endl;
} else {
std::cout << i << "," << j << " is NOT active" << std::endl;
}
}
}
return 0;
}
I'm really sorry for all this code... I tried to keep it as short as possible, but I thought it'd be better to post it all!
So yeah, my problem is the setActive function. When I just create a Tile and call its setActive function, everything works, but when I call it through the TileGrid object, it won't.
I have tried to solve this on my own for hours and I can't think straight anymore. I'm really desperate here, could you please have a look and maybe help me?
In your method:
Tile atIndex(unsigned int row, unsigned int col) const
you should return a reference to Tile:
Tile& atIndex(unsigned int row, unsigned int col)
now you are returning copy, and that is why modifications does not work. Also it should not be const, otherwise you will get compiler error.