Overloading [] [] statements in C ++

I am writing a 3x3 class in C ++.

glm :: mat3 provides access to the matrix data through the syntax of the [][] operator .
for example myMatrix[0][0] = 1.0f; will set the first row, the first entry of column 1.0f .

I would like to provide similar access. How can I overload [][] operator s?

I tried the following but get errors:

operator name must be declared as a function

 const real operator[][](int row, int col) const { // should really throw an exception for out of bounds indices return ((row >= 0 && row <= 2) && (col >= 0 && col <= 2)) ? _data[row][col] : 0.0f; } 

What is the correct way to overload this statement?

+2
source share
5 answers

There is no [][] operator, so you need to overload the [] operator twice: once on the matrix, returning a surrogate object for a row, and once for a returned surrogate row:

 // Matrix operator[] const row_proxy operator[](int row) const { return row_proxy(this, row); } // Proxy operator[] const real operator[](int col) const { // Proxy stores a pointer to matrix and the row passed into the first [] operator return ((this->row >= 0 && this->row <= 2) && (col >= 0 && col <= 2)) ? this->matrix->_data[this->row][col] : 0.0f; } 
+7
source

It would be easier to make a double operator() (int row, int col) const method. Instead of matrix[i][j] you just say matrix(i,j) .

+6
source

Typically, for multiple arguments, you want to use operator() rather than operator[] .

Hm, if this was not obvious, in C ++ there is no operator[][] . This is just operator[] applied twice. This means that if you want this notation, you must let the first return the result (an indexable thing or proxy), to which the second can be applied.

In the code below, outline some approaches, choose what you like:

 #include <iostream> #include <vector> template< int n > int& dummy() { static int elem = n; return elem; } struct Mat1 { int operator() ( int const x, int const y ) const { return dummy<1>(); } int& operator() ( int const x, int const y ) { return dummy<1>(); } Mat1( int, int ) {} }; struct Mat2 { int at( int const x, int const y ) const { return dummy<2>(); } int& at( int const x, int const y ) { return dummy<2>(); } Mat2( int, int ) {} }; struct Mat3 { struct At { At( int x, int y ) {} }; int operator[]( At const i ) const { return dummy<3>(); } int& operator[]( At const i ) { return dummy<3>(); } Mat3( int, int ) {} }; class Mat4 { protected: int get( int const x, int const y ) const { return dummy<4>(); } void set( int const x, int const y, int const v ) {} class AssignmentProxy { private: Mat4* pMat_; int x_; int y_; public: void operator=( int const v ) const { pMat_->set( x_, y_, v ); } int value() const { return pMat_->get( x_, y_ ); } operator int () const { return value(); } AssignmentProxy( Mat4& mat, int const x, int const y ) : pMat_( &mat ), x_( x ), y_( y ) {} }; public: int operator()( int const x, int const y ) const { return get( x, y ); } AssignmentProxy operator()( int const x, int const y ) { return AssignmentProxy( *this, x, y ); } Mat4( int, int ) {} }; class Mat5 { protected: int at( int const x, int const y ) const { return dummy<4>(); } int& at( int const x, int const y ) { return dummy<5>(); } class RowReadAccess { private: Mat5 const* pMat_; int y_; public: int operator[]( int const x ) const { return pMat_->at( x, y_ ); } RowReadAccess( Mat5 const& m, int const y ) : pMat_( &m ), y_( y ) {} }; class RowRWAccess { private: Mat5* pMat_; int y_; public: int operator[]( int const x ) const { return pMat_->at( x, y_ ); } int& operator[]( int const x ) { return pMat_->at( x, y_ ); } RowRWAccess( Mat5& m, int const y ) : pMat_( &m ), y_( y ) {} }; public: RowReadAccess operator[]( int const y ) const { return RowReadAccess( *this, y ); } RowRWAccess operator[]( int const y ) { return RowRWAccess( *this, y ); } Mat5( int, int ) {} }; struct Mat6 { private: std::vector<int> elems_; int width_; int height_; int indexFor( int const x, int const y ) const { return y*width_ + x; } public: int const* operator[]( int const y ) const { return &elems_[indexFor( 0, y )]; } int* operator[]( int const y ) { return &elems_[indexFor( 0, y )]; } Mat6( int const w, int const h ) : elems_( w*h, 6 ), width_( w ), height_( h ) {} }; int main() { using namespace std; enum{ w = 1024, h = 1024 }; typedef Mat3::At At; Mat1 m1( w, h ); Mat2 m2( w, h ); Mat3 m3( w, h ); Mat4 m4( w, h ); Mat5 m5( w, h ); Mat6 m6( w, h ); wcout << m1( 100, 200 ) // No fuss simple, but exposes element ref. << m2.at( 100, 200 ) // For those who don't like operators. << m3[At( 100, 200)] // If you really want square brackets mnemonic. << m4( 100, 200 ) // Hides element ref by using assignment proxy. << m5[200][100] // Ditto but with square brackets (more complex). << m6[200][100] // The minimum fuss square brackets, exposes elem ref. << endl; } 

It's good that after the publication of this code, I found that I did not completely hide the internal storage for Mat5 : it needs an additional proxy level, as in Mat4 . So this approach is really complicated. I would not do it ( Mat1 nice and light, I think), but some people think that proxies are cool, and the data is hidden even more cool and hellip;

To summarize, there is no β€œright” way to overload operator[] . There are many ways (as shown in the code above), each of which has some tradeoffs. In general, you'd better use operator() , because unlike operator[] it can take any number of arguments.

+5
source

There is no operator [][] . GLM mode does this by returning vec3& from the first [] . vec3 has its own operator overload [] . So two separate operator[] on two separate classes.

It also works GLSL. The first [] gets the column as a vector. The second takes the vector and gets the value from it.

+3
source

The expression foo[1][2] really interpreted as (foo[1])[2] , i.e. the [] operator is applied twice in a row, starting with the variable foo . The operator [][] cannot be overloaded.

+1
source

All Articles