Overloading operator [] - c++

I have a task to write a class matrix in C++ and there is a condition, to override the operator [] for matrix so if I have a matrix with name Matrix with this "Matrix[0][0]" I must take it's first element, on it's first line. I have represented the matrix with two dimensional dynamic array and templates (T **matrix). Could you help me, please?
PS: This method I'm using to create the two dimensional array:
template <class T>
T ** Matrix<T>::createMatrix(unsigned int rows, unsigned int cols)
{
T** matrix = new T*[rows];
for (unsigned int i = 0; i < rows; i++) {
matrix[i] = new T[cols];
}
return matrix;
}

i assume matrix is a member variable of type T** of Matrix.
template< class T >
T* operator []( Matrix<T>& m, unsigned int row )
{
// maybe remember rows and assert(row<rows);
return m.matrix[ row ];
}
Now you may write something like
Matrix<T> m(50,9999);
m[42][1337];
to access element 1337 in row 42.

You can do this with two classes. The matrix class overrides [] and returns a row object. The row object overrides [] and returns a scalar.

What you want to do is return a T* in operator[], as it can then have operator[] applied to it natively and get the result that you want. However, I want to point out that it's pretty bad practice to leave your pointers raw.

You can't do that natively in C++, but you could simply instanciate your matrix this way:
Matrix<Matrix<int>> m;
This way the first [ ] returns another matrix which will return the item you want. Of course a much better name for your class then would be Vector, and a wrapper class called Matrix that creates an internal Vector<Vector<T>>.

The method you are using to create the matrix doesn't have anything to do with a class, as your requirements state. You are creating a simple T**, it doesn't make a difference that you are doing it in a class method.
Creating a matrix of T that can be used as in matrix[i][j] means that the expression matrix[i] must return a type on which operator [] is also defined to return a T. Therefore, the usual way to do it is break it down in steps:
Matrix<T> operator[] (int) returns a MatrixRow<T>&
MatrixRow<T>& operator[] (int) returns a T&
There will also be const versions of these operators to be used when reading values from the matrix (non-const versions will be used when writing to the matrix).
So, at the minimum, you should create a class with this interface:
template <typename T>
class Matrix {
public:
Matrix(int rows, int cols);
const MatrixRow<T>& operator[] (int row) const;
MatrixRow<T>& operator[] (int row);
}
PS: This reads like a homework question, is it one?

Related

Generic Eigen Matrix/Vector object transfer to a custom matrix/vector container

So I have a custom made matrix/vector container (denoted MyContainer for simplicity) suited to a special purpose, and want to implement functionality for transferring the data of Eigen objects (Matrices, fixed, dynamic etc..) to my custom container. Thus I want to create a function similar to (illustrated with Eigen::MatrixXd)
template<class T>
void assign_eigen_object(MyContainer<T> &lhs, const Eigen::MatrixXd &rhs)
{
int n_rows = rhs.rows(), n_cols = rhs.cols();
lhs.resize(n_rows, n_cols);
for (int i = 0; i < n_rows; i++)
{
for (int j = 0; j < n_cols; j++)
{
lhs(i, j) = (T)rhs(i, j);
}
}
}
Is it then possible to create a templated function which takes into account all Eigen types (float dynamic matrix, double dynamic matrix, float fixed matrix, float partially fixed matrix etc..)?, or do I need to overload the function for the relevant objects? Maybe Eigen::Map can help me?
It should be as simple as changing the definition to this:
template<class T, typename TEigenType>
void assign_eigen_object(MyContainer<T> &lhs, const TEigenType &rhs)
{ ...
However, with the correct memory layout of MyContainer, you may be able to do even better and replace the nested loops with a single std::copy.
EDIT:
You might also want to add something like this to avoid possible missuse. I'm not entirely sure it will work with all eigen types though:
static_assert(std::is_same_v<std::decay_t<T>,
std::decay_t<typename TEigenType::value_type> >);
You probably want to define the function as a template like Benny K's answer.
If you have access to the raw storage of MyContainer (e.g. MyContainer::data()) you can use Eigen::Map for the implementation. Something like this:
Eigen::Map<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>> lhs_map(lhs.data(), n_rows, n_cols);
lhs_map = rhs.cast<T>();
Eigen::Map can be adapted to fit almost any regular memory layout (strides, column/row major, etc.) as long as it's a single block of memory.

Implement matrix as a class in C++

I need to implement matrix as a class in C++.
This is my class:
class {
private:
int rows, columns;
int **mat;
};
In the main, I need to start the matrix in the regular way. For example : m[0][0]=1;
I thought to overloading the operator[][] but it is forbidden.
I would like to get some help. thanks.
Instead, you could overload the function call operator (operator()()), to get something like this:
int operator()(int p_row, int p_column);
which is legal and clean. I would allow you to write something like this:
// Create and fill in matrix called 'm'...
int matrixElement = m(0, 0); // get element m[0][0]
// ...
Here is an example of how to overload this operator.
Let's say we have vector<vector<int>> xThe operator [][] is really (ignoring out of bounds) vector<int> b = x[0] then int = b[0] combined into one line. I.e accessing the first array then the subscript operator of the second.
Hope this helps.
You can store the data in a continuous array using std::vector and then supply your own indexing operator which returns a pointer to the beginning of the row.
class Matrix
{
int rows, columns;
std::vector<int> data;
public:
/*...*/
// The overloaded operator[] returns a pointer to the beginning
// of the requested row, which can then be indexed for the column
// without checking the boundaries.
int* operator[](int r){
return &data[r*columns];
}
};
Using a vector of vectors is less efficient because the data gets spread to different memory locations. If you need bounds checking you can wrap the pointer in your own class and overload its operator[].

Templates with pointers, creating 2d array

I got a little problem with templates and pointer. I'm trying to create a 2d array for some different matrices with different types. I have to do it with templates and references where it makes sense.
My main function looks like this, I'm not allowed to change it:
int main(){
int row, column;
cin >> row;
cin >> column;
int** M1;
double** M2;
reserve(M1, row, column);
reserve(M2, row, column);
return 0;
}
So my reserve function would look something like this:
template <typename S>
void reserve(S &x, int row, int column){
x = new S*[row];
for(int i = 0; i < row; ++i) {
x[i] = new S[column];
}
}
My problem is that I'm not getting the solution for this function. I tried it every way I could think about but nothing works.
I think the problem is that I'm not working correct with the type** pointer in combination with the type-parameter. In the version I posted above, im getting errors like:
error: cannot convert ‘int****’ to ‘int**’ in assignment x = new S*[row];
Would love if someone could help me fixing this function.
Changing the signature of reserve to this should fix the compile error
template <typename S>
void reserve(S **&x, int row, int column)
Alternatively, you can implement reserve so that it returns the newly allocated array
template <typename S>
S** reserve(int row, int column)
{
S** x = new S*[row];
for (int i = 0; i < row; ++i) {
x[i] = new S[column];
}
return x;
}
Remember to delete the array using delete [] when you are done using it:)
Maybe something like this might help you; try to encapsulate the whole concept into a class object like this:
template<typename T>
class Matrix {
public:
typedef std::vector<T> Row;
private:
std::vector<Row> Mat;
unsigned numberRows;
unsigned numberColumns;
public:
Matrix();
explicit Matrix( std::vector<Row>& vRows );
Matrix( unsigned numRows, unsigned numColumns );
Matrix( unsigned numRows, unsigned numColumns, T** data );
~Matrix();
private:
void reserve( unsigned int numRows, unsigned int numColumns );
};
Where this reserve() method is part of the class object where only this class has access to it. This would act as a helper function for your class in implementing its multiple constructors. If you want to use dynamic memory for the elements this can be expanded to this:
template<typename T>
class Matrix {
public:
typedef std::vector<std::shared_ptr<T>> Row;
private:
std::vector<Row> Mat;
// All Else Would Be The Same; Only The Internal Methods Would Slightly
// Vary Due To The Use Of Smart Pointer And Dynamic Memory.
};
Then in your main this will simplify code.
int main() {
// Using Default Constructor
Matrix<float> fMat1;
// Using std::vector<Row> To Construct A Matrix
Matrix<int>::Row row1;
Matrix<int>::Row row2;
Matrix<int>::Row row3;
std::vector<Matrix<int>::Row> vRows
Matrix<int> iMat2( vRows );
// A Construct That Knows The Size Of The Matrix;
// But Doesn't Have The Data
Matrix<double> dMat3( 4, 4 ); // This Will Create A Size Of 4x4 Of
// Doubles And Initialize Everything To 0
// Same As Above, But Passing In Raw Data By Double Pointer.
float** pData = nullptr;
// Populate Pointer's Elements
unsigned int row, col;
// Store Size Of Row & Col Based On Pointer's Elements
Matrix<float>( row, col, pData );
return 0;
}
And that is about it! The constructors shouldn't be that hard to implement. And if you are only working with stack objects the first definition of the class will work, but if you need dynamic memory of all objects the second one will suite your needs and the use of smart pointers makes the cleaning up of dynamic memory much cleaner, easier and safer. Less prone to memory leaks.
This would also allow you to create a matrix when you have the data available upon creation of the matrix; or to make an empty matrix container available to set aside memory for later on when you are ready to populate it. You would just have to add the necessary methods to set, get data elements, and any appropriate operator overloads for performing basic operations. Maybe some public methods to do common work on data or to test if data is in matrix, etc.
Because this Matrix class is template the way it is; it is not subject to just basic raw day types. This can store class objects, structure, function pointers, events, threads, files and even more!

Implementing the A(:,k)=b; Matlab-like syntax in a C++ matrix library

I have developed an expression templates-based C++ matrix class of my own. I have overloaded the () operator so that I can read or write element matrices as, for example,
cout << A(i,j) << endl;
and
A(i,j)=b;
respectively.
I have also implemented a Range class to enable Matlab-like reads as
cout << A(Range(3,5),Range(0,10)) << endl;
The template Matrix class is exemplified as
template <typename OutType>
class Matrix
{
private:
int Rows_; //number of Rows
int Columns_; //number of Columns
OutType *data_; //row-major order allocation
public:
// --- Access operators
inline OutType & operator()(const int i, const int j) { return data_[IDX2R(i,j,GetColumns())]; }
inline OutType operator()(const int i, const int j) const { return data_[IDX2R(i,j,GetColumns())]; }
// --- SubExpressions - Range Range
inline Expr<SubMatrixExpr<const OutType*,OutType>,OutType> operator()(Range range1, Range range2)
{ typedef SubMatrixExpr<const OutType*,OutType> SExpr;
return Expr<SExpr,OutType>(SExpr(data_,Rows_,Columns_,range1.numelements_,range2.numelements_,range1.start_,range1.step_,range2.start_,range2.step_),
range1.numelements_,range2.numelements_);
}
}
I would now like to enable Matlab-like assignments as
A(Range(3,5),Range(0,10))=B;
where B is an appropriate matrix.
I think that, to achieve the Matlab-like syntax above, two possibilities would be
overloading the () operator, so that it returns an array of pointers, and then overloading the = operator so that the latter could act between an array of pointers and a Matrix;
exploit the already performed overload of the () operator indicated above and overloading the = operator so that the latter could act between an expression and a Matrix.
Maybe the first option is not very convenient, especilly for very large matrices.
Am I correct? Are there other more efficient/effective possibilities using perhaps more sophisticated C++ features (e.g., move semantics)?
Thank you very much for your help.
I think your best bet is to have a non-const version of operator()(Range, Range) return a proxy object that has an overloaded assignment operator that knows how to assign to a range (back into the original matrix for example).

C++ Matrix Class with Operator Overloading

I was implementing a small dense matrix class and instead of plan get/set operators I wanted to use operator overloading to make the API more usable and coherent.
What I want to achieve is pretty simple:
template<typename T>
class Matrix
{
public:
/* ... Leaving out CTOR and Memory Management for Simplicity */
T operator() (unsigned x, unsigned y){/* ... */ }
};
Matrix<int> m(10,10);
int value = m(5,3); // get the value at index 5,3
m(5,3) = 99; // set the value at index 5,3
While getting the value is straight forward by overloading operator(), I can't get my head around defining the setter. From what I understood the operator precedence would call operator() before the assignment, however it is not possible to overload operator() to return a correct lvalue.
What is the best approach to solve this problem?
I dispute that "it's not possible" to do the correct thing:
struct Matrix
{
int & operator()(size_t i, size_t j) { return data[i * Cols + j]; }
const int & operator()(size_t i, size_t j) const { return data[i * Cols + j]; }
/* ... */
private:
const size_t Rows, Cols;
int data[Rows * Cols]; // not real code!
};
Now you can say, m(2,3) = m(3,2) = -1; etc.
The answer to your question is what Kerrek already stated: you can provide an overload by changing the signature of the operator, which in this case can be achieved by modifying the const-ness of the function.
But I would recommend that you at least consider providing a separate setter for the values. The reason is that once you return references to your internal data structures you loose control of what external code does with your data. It might be ok in this case, but consider that if you decided to add range validation to the implementation (i.e. verify that no value in the matrix is above X or below Y), or wished to optimize some calculation on the matrix (say the sum of all of the elements in the matrix is an often checked value, and you want to optimize away the calculation by pre-caching the value and updating it on each field change) it is much easier to control with a method that receives the value to set.