I would like to have a simple matrix class with the feature of slicing to avoid nested for-loops. For that, I have written the following class
// matrix.hpp
#include <cstddef>
#include <iostream>
#include <vector>
template <typename T>
class SubMatrix;
template <typename T>
class Matrix
{
std::vector<T> _matrix;
size_t _rows;
size_t _cols;
public:
Matrix(const size_t rows, const size_t cols) : _matrix(rows * cols),
_rows(rows),
_cols(cols) {}
Matrix(const size_t rows, const size_t cols, const T init)
: _matrix(rows * cols, init),
_rows(rows),
_cols(cols) {}
Matrix(Matrix &other) : _matrix(other._matrix),
_rows(other._rows),
_cols(other._cols) {}
~Matrix() {}
Matrix &operator=(Matrix &other)
{
for (size_t i = 0; i < _matrix.size(); i)
_matrix[i] = other._matrix[i];
_rows = other.rows();
_cols = other.cols();
return *this;
}
T operator()(const size_t i, const size_t j) const
{
return _matrix.at(_cols * i j);
}
T &operator()(const size_t i, const size_t j)
{
return _matrix.at(_cols * i j);
}
/*
i, j: initial row and column, respectively
p: number of rows from i
q: number of columns from j
*/
void slice(const size_t i, const size_t j,
const size_t p, const size_t q,
Matrix &other)
{
size_t index{0};
size_t cont{0};
for (size_t ii = i; ii < i p; ii )
{
for (size_t jj = j; jj < j q; jj )
{
index = _cols * ii jj;
_matrix[index] = other._matrix[cont];
cont;
}
}
}
void print()
{
std::cout << '\n';
for (size_t i = 0; i < _rows; i)
{
for (size_t j = 0; j < _cols; j)
std::cout << this->operator()(i, j) << ' ';
std::cout << '\n';
}
}
SubMatrix<T> operator()(const size_t i,
const size_t j,
const size_t p,
const size_t q)
{
SubMatrix<T> sub_matrix(i, j, p, q, *this);
return sub_matrix;
}
};
To have the slicing feature as
A(i, j, p, q) = B
where A
and B
are matrices, i
and j
are the initial indices, and p
and q
are the number of lines from i
and q
the number of lines from j
, I have written the following proxy class
template <typename T>
class SubMatrix
{
size_t _i, _j, _p, _q;
public:
Matrix<T> _matrix;
SubMatrix(const size_t i,
const size_t j,
const size_t p,
const size_t q,
Matrix<T> &matrix) : _i(i),
_j(j),
_p(p),
_q(q),
_matrix(matrix) {}
SubMatrix<T> &operator=(Matrix<T> &matrix)
{
_matrix.slice(_i, _j, _p, _q, matrix);
return *this;
}
};
The code ran smoothly, but the slicing is not being performed correctly. The matrix B
is not assigned to A
.
// main.cpp
#include "matrix.h"
int main()
{
Matrix<double> A(5, 5, 1.0);
Matrix<double> B(3, 3, 9.0);
A.print();
B.print();
A(1, 1, 3, 3) = B;
A.print();
return 0;
}
The output of the code is:
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 9 9 9 9 9 9 9 9 9 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
Does anyone know why the values of B
is not being assigned to A
?
CodePudding user response:
SubMatrix<T> Matrix::operator()
creates a temporary copy of its own internal _matrix
member. Next this copy is modified by the assignment from B
.
But the original A
remains unchanged. When you use a reference instead, the assignment operator will assign to the original _matrix
member:
template <typename T>
class SubMatrix
{
// ...
Matrix<T> &_matrix;
public:
// ...
};
Unrelated, but _matrix
should be a private member.
CodePudding user response:
What your code does is basically this:
#include <iostream>
struct Proxy { int x; };
struct twoNumbers {
int a = 0;
int b = 0;
Proxy aset() {return {a};}
Proxy bset() {return {b};}
};
int main() {
twoNumbers A;
auto p = A.aset();
p.x = 42;
std::cout << A.a;
}
The Proxy
stores a copy of the value and modifying that copy has no effect on the original value.
What you want is Proxy
holding a reference that allows to modify the original. Something like this:
#include <iostream>
struct Proxy { int& x; };
struct twoNumbers {
int a = 0;
int b = 0;
Proxy aset() {return {a};}
Proxy bset() {return {b};}
};
int main() {
twoNumbers A;
auto p = A.aset();
p.x = 42;
std::cout << A.a;
}
42