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.