Overload index operator to mimic POD multi-dimensional array? - c++

I have an existing class, which is structured in the following way:
class Matrix
{
public:
float Data[4][4];
// ... methods
};
And subsequently used in the following ways:
Matrix m;
m.Data[0][0] = 1.0f;
float local = m.Data[0][0];
//...
I would like to replace the Data member with an overloaded indexing operator, so I can perform range checking on the indices used. While I can change the Matrix class itself, and the implementations of its member functions, I cannot modify its usages in existing code, so any solution requires that the usage syntax remains identical. It's also desirable that the solution doesn't change sizeof(Matrix). Is there a way to achieve this?

Generally for this sort of thing, you need to use a proxy class to handle the second indexing operator. It would look something like this and go in the private section of your Matrix class. I'll leave out the bounds-checking (it shouldn't be hard for you to add that yourself).
class Proxy {
Matrix& ref;
size_t i;
public:
Proxy(Matrix& on, size_t i) : ref(on), i(i) {}
float operator[] (size_t j) {
return ref.Data[i][j];
}
};
Then just have your Matrix::operator[] return an instance of this class:
Proxy operator[] (size_t i) {
return Proxy(*this, i);
}
Note that if you want a const overload (ie, you want to use the indexing operator on const Matrix objects), you'll need a separate ConstProxy class which has const Matrix& ref instead of Matrix& ref but is otherwise identical.
There is also the option of returning a reference to an array. (Note: as one of the comments pointed out, this doesn't help much with bound-checking, but I think it's interesting, so I'll leave it here.)
float (&operator[](size_t i))[4] {
return Data[i];
}
The syntax for that is quite arcane, and I believe it doesn't work in Visual Studio 2013, but you can make it a bit cleaner with a typedef.
using Proxy = float[4];
Proxy& operator[](size_t i) {
return Data[i];
}
There's one more option, if you don't mind abandoning square-bracket indexing. You can overload the function call operator like this:
float operator()(size_t i, size_t j) {
return Data[i][j];
}

Another way is define a the proxy class with the semantic of a vector
class Matrix
{
public:
struct SubMatrix
{
class Vector
{
public:
Vector(float *data) : Data(data) {}
float &operator[](int index) { return Data[index]; }
private:
float *Data;
};
Vector operator[](int index)
{
return Vector(Data[index]);
}
float Data[4][4];
};
SubMatrix Data;
// ... methods
};
Then you can use it this way:
Matrix m;
float f = m.Data[1][2];

Related

C++ is there a way to overload operator [][]? [duplicate]

I have class CMatrix, where is "double pointer" to array of values.
class CMatrix {
public:
int rows, cols;
int **arr;
};
I simply need to access the values of matrix by typing:
CMatrix x;
x[0][0] = 23;
I know how to do that using:
x(0,0) = 23;
But I really need to do that the other way. Can anyone help me with that?
At the end I did it this way...
class CMatrix {
public:
int rows, cols;
int **arr;
public:
int const* operator[]( int const y ) const
{
return &arr[0][y];
}
int* operator[]( int const y )
{
return &arr[0][y];
}
....
You cannot overload operator [][], but the common idiom here is to use a proxy class, i.e. overload operator [] on your Matrix class to return an instance of a different class which then has operator [] overloaded on it.
For example:
class CMatrix {
public:
class CRow {
friend class CMatrix;
public:
int& operator[](int col)
{
return parent.arr[row][col];
}
private:
CRow(CMatrix &parent_, int row_) :
parent(parent_),
row(row_)
{}
CMatrix& parent;
int row;
};
CRow operator[](int row)
{
return CRow(*this, row);
}
private:
int rows, cols;
int **arr;
};
There is no operator[][] in C++. However, you can overload operator[] to return another structure, and in that overload operator[] too to get the effect you want.
You can do it by overloading operator[] to return an int*, which is then indexed by the second application of []. Instead of int* you could also return another class representing a row, whose operator[] gives access to individual elements of the row.
Essentially, subsequent applications of operator[] work on the result of the previous application.
If you create a matrix using Standard Library containers, it's trivial:
class Matrix {
vector<vector<int>> data;
public:
vector<int>& operator[] (size_t i) { return data[i]; }
};
Some support for this has been added for containers in C++23: Multidimensional subscript operator
Although the syntax used is v[x, y, z] rather than v[x][y][z].
You could operator[] and make it return a pointer to the respective row or column of the matrix.
Because pointers support subscripting by [ ], access by the 'double-square' notation [][] is possible then.
Other answers tell you how you can do it, but...
Don’t do that.
Instead, overload operator ().
int & operator () ( size_t row, size_t col )
{
// maybe validate `row` and `col` first?
return arr[row * cols + col];
}
Why not?
The C++ FAQ explains it all. Straight from the horses’ mouths.
How do I create a subscript operator for a Matrix class?
Why shouldn’t my Matrix class’s interface look like an array-of-array?
I still don’t get it. Why shouldn’t my Matrix class’s interface look like an array-of-array?
tl;dr : encapsulation and safety

How to access to subsequence of a valarray considering it as a 2D matrix in C++

I'm learning C++, so please be patient with me.
I have a std::valarray in which there are double elements and I consider it as a 2D matrix.
class Matrix {
valarray<double> elems;
int r, c;
public:
/* type? operator[](int r) { return ? } */
//...
}
I want to overload the operator[], so that I can get a row of the matrix, and after that, I want have the m[r][c] access operator.
Is there any way to get a row, as a sequence of double using std::slice in the valarray, so that if I change a value, it is changed also in the matrix?
I've read this definition in valarray:
std::slice_array<T> operator[]( std::slice slicearr );
My operator[] must have std::slice_array<double>& as returned type?
Thanks.
I don't think std::slice and std::slice_array is what you're looking for, especially the latter is nothing but a helper type with a very limited public interface. You can instead return an proxy object. Here's a possible example of how to implement that.
class Matrix {
/* ... */
class RowProxy {
public:
RowProxy(std::valarray<double>& elems, int c, int row) :
elems(elems), c(c), row(row) {}
double& operator[](int j)
{
return elems[row*c + j];
}
private:
std::valarray<double>& elems;
int row;
int c;
};
RowProxy operator[](int i)
{
return RowProxy(elems, c, i);
}
};
This way, you can access the data with two operator[].
Matrix m(2, 4); // Assuming the ctor initializes elemens with row*column
m[0][0] = 1.234;
m[1][0] = 2.234;
m[1][3] = -52.023;
Note that both Matrix and RowProxy are missing overloads and proper handling for const-ness, and variable names are poor. Also, you might want to think about an out-of-bounds error handling strategy. But it may serve as a starting point for your implementation.

How to recognize the assignment operator?

I've got class with overloaded [] and I need to make it to recognize, when I try to set the values to the array. I assume, that I'll have to overload the operator =, nevertheless I don't know, how shall that whole stuff look like. Part of my code:
class Matrix {
public:
Matrix(int x, int y);
~Matrix(void);
Matrix& operator =(const Matrix &matrix); //ok...this is probably wrong...
class Proxy {
public:
Proxy(double* _array) : _array(_array) {
}
double &operator[](int index) const {
return _array[index];
}
private:
double* _array;
};
Proxy operator[](int index) const {
return Proxy(_arrayofarrays[index]);
}
Proxy operator[](int index) {
return Proxy(_arrayofarrays[index]);
}
int x, y;
double** _arrayofarrays;
};
So I just need to be able to recognize when I try to set Matrix matrix(3,3); matrix[0][0]=1;
Everything else works allright, so I assumed that it's not needed to paste the whole code
It looks like you want something which is not directly possible: operator[][].
You can emulate the behavior of this by using an intermediate class:
Since a Matrix class is typically indexed as [rows][columns], you can
have the first operator method return the corresponding Row object.
The row class can than overload the operator[] and return the corresponding
element.
Row& Matrix::operator[](int r);
double& Row::operator[](int c);
Now when you create your matrix object, you can index it as expected:
Matrix matrix(3,3);
matrix[0][0] = 1;
The last line is then equivalent to calling:
matrix.operator[](0).operator[](0) = 1;
To check for out-of-bounds indices, store the matrix sizes:
Proxy operator[](int index) {
assert(index < num_rows);
return Proxy(_arrayofarrays[index]);
}
double &operator[](int index) const {
assert(index < num_cols);
return _array[index];
}
As Aldo suggeested, Proxy can be passed the array length value in it's constructor:
Proxy(double* _array, int _length) : _array(_array), num_cols(_length){
}
As a general rule of thumb, if you're passing a raw array to a function, you will almost always want to pass the length of that array as well.
Your Proxy::operator[] overload is returning a double&. This double& is the object that will eventually be assigned to by client code, and you can't intercept that (at least not easily). Probably what you need to do is to check the index parameter in your operator[] overloads, and throw your own exception there rather than passing that index along to your internal arrays.

C++ multidimensional array operator

it is possible to overload somehow operator for multidimensional array?
Something like:
class A {
...
int& operator[][] (const int x, const int y);
...
}
Nope, that is not possible. There are two alternatives, though:
You can have operator[] return an array of a smaller dimension (For a 3D array, it will return a 2D array, for a 2D array it will return a 1D array, and for a 1D array, it will return a single element). Then you can "string them together" with the syntax you want. (arr[x][y][z])
Alternatively, you can overload operator(), because that can take multiple arguments.
Then you can use it like this, to index into a 3D array for example: arr(x,y,z)
But you can't overload [][] or [][][] as a single operator.
Not directly, but you can achieve the same functionality overloading operator[]() and having it return something that supports operator[]() itself.
For example:
class A {
std::vector<std::vector<int> > vec;
public:
std::vector<int>& operator[] (int x)
{
return vec[x];
}
};
would allow you to write:
A a;
//...
int y = a[1][2];
because a[1] returns a std::vector<int> to which you can apply operator[](2).
You need to overload operator[] and make it return a new class which only has another operator[].
No, there's just operator[]. As an alternative, you can overload:
int &operator()(int x, int y);
You can use that:
m(4, 5);
Since C++23, an overloaded operator[] will now take 0 or more arguments which behaves exactly the same as operator()
class A {
// ...
int& operator[](std::size_t x, std::size_t j);
// ...
};
invocation:
A a = /* ... */;
a[1, 2]; // equivalent to 'a.operator[](1, 2)'
It is a single operator being used twice to dereference. You can dereference [] operator and perform the functionality and usage by using it as [][] by changing the return type.
There's no operator like that. I implemented, some times ago, a matrix trying to be close to the stl standards.
And I used this method: first I've overloaded the operator[] to return another class that I called _C_row:
_C_row operator[](size_type index) { return _C_row(/*some parameters*/); } ///< This operator is overloaded to permit the use of double pointer notation.
_C_row operator[](size_type index) const { return _C_row(/*some parameters*/); } ///< This operator is overloaded to permit the use of double pointer notation.
And in _C_row I overloaded more than the operator[]:
value_type operator*() { return _r[0]; }
pointer operator->() { return _i[_idx]; }
double_pointer operator&() { return &(_i[_idx]); }
reference operator[](size_type col) { return _r[col]; }
const_reference operator[](size_type col) const { return _r[col]; }
I found this solution is very flexible. I hope my answer could be useful for you.
As mentionned before, there is no such thing as operator[][].
However, here is an an implementation using nested classes similar to what "jalf" proposed. For sake of simplicity, I hardcoded a 3x3 raw array.
class Array2D final{
public:
class PartialArr final{
private:
friend Array2D;
PartialArr(Array2D* ptr, int index) :original(ptr), firstIndex(index) {}
int firstIndex;
Array2D* original;
public:
int& operator[](int index) { return this->original->data[firstIndex][index]; }
};
PartialArr operator[](int index) { return PartialArr(this, index); }
private:
int data[3][3];
};
This solution prevents the user of Array2D to manipulate the data directly when indexing only the first dimension of the array.
const versions of both operator[] could also be added to make the class complete.

2D matrix and overloading operator() / ugly syntax

I'm using a 2D matrix in one of my projects. It's something like it is suggested at C++ FAQ Lite.
The neat thing is that you can use it like this:
int main()
{
Matrix m(10,10);
m(5,8) = 106.15;
std::cout << m(5,8);
...
}
Now, I have a graph composed of vertices and each vertex has a public (just for simplicity of the example) pointer to 2D matrix like above. Now I do have a pretty ugly syntax to access it.
(*sampleVertex.some2DTable)(0,0) = 0; //bad
sampleVertex.some2DTable->operator()(0,0) = 0; //even worse...
Probably I'm missing some syntactic sugar here due to my inexperience with operator overloading. Is there a better solution?
Consider using references instead of pointers (provided, it can't be null and you can initialize in the constructor).
Consider making a getter or an instance of a matrix wrapper class for a vertex that returns a reference to 2D matrix (provided, it can't be null).
sampleVertex.some2DTable()(0,0) = 0;
sampleVertex.some2DTableWrap(0,0) = 0;
However, to me it sounds like a non-issue to justify going through all the trouble.
If you have a pointer to a Matrix, e.g. as a function parameter that you can't make a reference (legacy code, e.g.), you can still make a reference to it (pseudo code):
struct Matrix {
void operator () (int u, int v) {
}
};
int main () {
Matrix *m;
Matrix &r = *m;
r (1,1);
}
You're basically limited to (*sampleVertex.some2DTable)(0,0). Of course, if you don't need reseating, why not store the actual values in the matrix instead?
Alternatively, make the pointer private and make an accessor (note: the following examples assume a matrix of EntryTypes):
Matrix& Vertex::GetTableRef()
{
return *some2DTable;
}
// or
Matrix::EntryType& Vertex::GetTableEntry(int row, int col)
{
return (*some2DTable)(row,col);
}
// way later...
myVertex.GetTableRef()(0,0) = 0;
// or...
myVertex.GetTableEntry(0,0) = 0;
Or, just define an inline function to do this for you if you can't change the class Vertex:
// in some header file
inline Matrix& GetTableRef(Vertex& v)
{
return *v.some2DTable;
}
// or you could do this
inline Matrix::EntryType& GetTableEntry(Vertex& v, int row, int col)
{
return (*v.some2DTable)(row, col);
}
// later...
GetTableRef(myVertex)(0, 0) = 0;
// or
GetTableEntry(myVertex, 0, 0) = 0;
Finally, don't forget that you don't have to use operator overloading. STL collections implement an at() member function, which is checked, as opposed to operator[] which is unchecked. If you don't mind the overhead of bounds checking, or if you just want to be nonstandard, you could implement at() and then just call myVertex.some2DTable->at(0,0), saving a bit of a syntactic headache altogether.
There is no C++ syntactic sugar that will ease the pain of what you describe:
(*sampleVertex.some2DTable)(0,0) = 0; //bad
sampleVertex.some2DTable->operator()(0,0) = 0; //even worse...
In this situation, I would either have the graph return a reference instead of a pointer, or have the matrix define a function which calls the operator():
inline matrixType &Matrix::get( int x, int y ){ return operator()(x,y); }
Then, the syntax isn't quite as ugly for the vertex example:
sampleVertex.some2DTable->get(0,0) = 0;
I would add a function that returns you a ref like rlbond recommends. For a quick fix or if you don't have control over the source of it, i would go with this:
sampleVertex.some2DTable[0](0,0) = 0; // more readable
That's actually equivalent, because the following holds if a is a pointer to a defined class:
*a == *(a + 0) == a[0]
See this long discussion on comp.lang.c++ about that same problem with good answers.
This is the best way without changing your code:
//some2DTable is a pointer to a matrix
(*sampleVertex.some2DTable)(0,0)
You could also instead make some2DTable a reference to a matrix instead of a pointer to a matrix. Then you would have simplified syntax as in your first code sniplet.
//some2DTable is a reference to a matrix instead of a pointer to a matrix
sampleVertex.some2DTable(0,0)
Or you could keep some2DTable a pointer to a reference and simply store a reference variable to it and use that in the context of your code block.
I'd change the way you get hold of "sampleVertex.some2DTable" so it returns a reference.
Either that or create the reference yourself:
Matrix& m = *sampleVertex.some2DTable;
m(1,2) = 3;
I don't know if it's worth the trouble, but you could do:
class MatrixAccessor {
private:
Matrix2D* m_Matrix;
public:
MatrixAccessor(Matrix2D* matrix) : m_matrix(matrix) { }
double& operator()(int i, int j) const { return (*m_Matrix)(i,j); }
Matrix2D* operator->() const { return m_Matrix; }
void operator=(Matrix2D* matrix) { m_Matrix = matrix; }
};
Provided the original operator() returns a reference (as it is in many matrix classes).
Then you provide that MatrixAccessor in your vertex class:
class Vertex {
Matrix2D* myMatrix;
public:
MatrixAccessor matrix;
Vertex(Matrix2D *theMatrix) : myMatrix(theMatrix), matrix(theMatrix) { }
};
Then you can write:
Vertex v;
v.matrix(1,0) = 13;
v.matrix->SomeOtherMatrixOperation();
EDIT
I added const keywords (thanks to #phresnel for bringing up the topic) in order to make the solution semantically equivalent to a solution only presenting a public Matrix2D-pointer.
An advantage of this solution is that constness could be transferred to the matrix object by adding two non-const versions of the operator()() and operator->() (i.e. the matrix cannot be modified on const vertices) and changing the const ones to return a const double& and const Matrix2D* respectively.
That would not be possible when using a public pointer to the matrix object.
You could implement Matrix::operator (int,int) by calling a member function and use that one directly when dealing with pointers.
class Matrix
{
public:
float ElementAt( int i, int j ) const { /*implement me*/ }
float operator() ( int i, int j ) const { return ElementAt( i, j ); }
...
};
void Foo(const Matix* const p)
{
float value = p->ElementAt( i, j );
...
}
void Bar(const Matrix& m)
{
float value = m(i,j);
}