I am writing a matrix class in c++ and trying to overload some operator like = and >> and << etc.
I was unable to overload operator [][] for matrix class.
if i have an object of class matrix like M1 then i can use this way for giving value to each element:
M1[1][2]=5;
OR
int X;
X=M1[4][5];
Just overload operator[] and make it return a pointer to the respective row or column of the matrix. Since pointers support subscripting by [], access by the 'double-square' notation [][] is possible then.
You can also overload operator() with two arguments.
There is no operator[][] in C++. You have to return a helper object and then overload operator[] for that too, to have this kind of access.
You could overload operator[]. So if you would like to use matrix that way, you should make matrix as array of vectors.
class Matrix
{
...
Vector & operator[]( int index );
...
};
and
class Vector
{
...
double & operator[]( int index );
...
};
Finally:
Matrix m;
...
double value = m[i][j];
...
there is no operator[][], you can implement operator[] to return a reference to the row/column object, in which you can implement the operator[] to return you the cell reference.
You can do something like the following to avoid all that hassle..
struct loc
{
int x;
int y;
};
then in your operator[] overload, accept a loc, something like
T& operator[](loc const& cLoc)
{
// now you have x/y you can return the object there.
}
To call, you can simply do something like:
matrix[loc(2,3)] = 5;
Actually, I did just that in my own matrix class a few years ago. In this case, I defined a matrix template class that contained the snippet, below.
I was then able to iterate and assign as follows:
for(size_t k=1; k<n; ++k) {
minor[p][k-1]=major[j][k];
}
I hope this helps.
// //////////////////////////////////////////////////////////////////////////////
// list is internal vector representation of n x m matrix
T* list;
// Proxy object used to provide the column operator
template < typename T >
class OperatorBracketHelper
{
Matrix < T > & parent ;
size_t firstIndex ;
public :
OperatorBracketHelper ( Matrix < T > & Parent , size_t FirstIndex ) :
parent ( Parent ), firstIndex ( FirstIndex ) {}
// method called for column operator
T & operator []( size_t SecondIndex )
{
// Call the parent GetElement method which will actually retrieve the element
return parent.GetElement ( firstIndex , SecondIndex );
}
};
// method called for row operator
OperatorBracketHelper < T > operator []( size_t FirstIndex )
{
// Return a proxy object that "knows" to which container it has to ask the element
// and which is the first index (specified in this call)
return OperatorBracketHelper < T >(* this , FirstIndex );
}
T & GetElement ( size_t FirstIndex , size_t SecondIndex )
{
return list[FirstIndex*cols+SecondIndex];
}
I am exactly working on a matrix class and I decided to first create an Array class which has a dynamic 2-D array. So, well just as you, I confronted this obstacle that how I can overload two square brackets. How I approached this case is very simple; I overloaded the square brackets operator twice as member functions. First, I overloaded [] so as to return a pointer pointing to the desired row, so to speak, and then the following member function (i.e. again operator [] overloaded) returns a lvalue of the same type as the array's elements.
However, note that the index you inter to invoke the former overloaded operator [] must be saved somewhere so that you may use it in the latter overloaded operator []. For this reason I simply added a new member of the type int to the class Array (which I've named it "test" in my code below).
class Array {
private:
double **ptr; int test;
... /* the rest of the members includes the number of rows and columns */
public:
Array(int=3,int=3); // Constructor
Array(Array &); // Copy Constructor
~Array(); // Destructor
void get_array();
void show_array();
double* operator[] (int);
double operator[] (short int);
...
};
...
double* Array::operator[] (int a) {
test = a;
double* p = ptr[test];
return p;
}
double Array::operator[] (short int b) {
return ((*this)[test][b]);
}
Therefor, as an example, in main I can simply write:
int main(){
Array example;
cout << example[1][2];
}
I hope this would help you.
You can't overload [][] as such, since there isn't such an
operator. You can overload [] to return something which also
has an [] defined on it (a proxy); in the simplest case,
something like a double* will work, but it's usually better,
although a bit more work, to use a full class. (Place to add
bounds checking, for example.)
Alternatively, you can overload (x,y). Depending on who you
ask, one format or the other is "better". (In fact, it's
strictly a question of style.)
Template matrix class
template <uint8_t rows, uint8_t cols, typename T>
class MatrixMxN {
public:
T* operator[](uint8_t f_row) {
return &m_val[f_row * cols];
}
protected:
T m_val[rows*cols];
};
and here is object of matrix with 3 row, 4 column and integer type.
MatrixMxN<3, 4, int32_t> M;
M[2][3] = 10;
std::cout << M[2][3] << std::endl;
Related
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
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
Below is the snippet of code where the error lies, the line
a[i][j] = m[i][j] + w[i][j];
returns an error
lvalue required as left operand of assignment
I can't find an answer that applies to arrays, my Matrix is defined as follows:
Matrix::Matrix() {
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
coords[i][j] = 0.0f;
}
const Matrix operator+(const Matrix &m, const Matrix &w) {
Matrix a;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 4 ; j++)
a[i][j] = m[i][j] + w[i][j]; // <----- error
return a;
}
Here is the operator[]
How do I return by reference
const Vector Matrix::operator[](int i) const{
switch(i)
{
case 0: return Vector (coords[i][0], coords[i][1], coords[i][2]);
case 1: return Vector (coords[i][0], coords[i][1], coords[i][2]);
case 2: return Vector (coords[i][0], coords[i][1], coords[i][2]);
}
}
The error is actually "lvalue required as left operand of assignment".
It means that your a[i][j] is giving you a temporary object. This happens when you return from a function by value. A function call that returns by value is an rvalue expression, and you cannot use an rvalue expression as the left operand of an assignment. You need to change the implementation of operator[] on both the Matrix and the helper class that Matrix::operator[] returns so that they return by reference. A function call that returns by reference is an lvalue expression and will allow you to assign to it.
template <typename T>
Vector<T>& Matrix<T>::operator[](int index) { ... }
template <typename T>
T& Vector<T>::operator[](int index) { ... }
Of course, this makes sense. If your operator[]s didn't return by reference, how would assigning to the value returned by them have any effect on the contents of the Matrix?
In response to your edit:
You have a problem with the design of your class. The Matrix class appears to store a 3-by-3 array of floats called coords. However, when you use Matrix::operator[], it copies the values from a row of coords into a Vector object. They are copies. You then return that Vector by value, which copies the Vector and its contained values out of the function. Anything you do to that returned Vector will only affect that copy.
In addition to this, your switch statement is totally pointless. Every case is exactly the same. You just need to use i as the array indices and not switch on it.
Also, if you're going to allow people that call operator[] to modify the contents of your Matrix, then the operator[] function must not be const.
There are a few alternatives that will fix your problem. The first is to just return a float* instead and scrap your plan with Vector:
float* Matrix::operator[](int i) {
return coords[i];
}
That's a very simple solution but does involve passing a raw pointer around. The raw pointer can be used like an array, allowing you the syntax m[i][j].
You could do the same as the Eigen library and instead provide a operator() that takes two arguments, the row index and column index:
float& Matrix::operator()(int i, int j) {
return coords[i][j];
}
Note that the float is being returned by reference: float&. This means that is modifiable from outside the call to operator(). Here, you would index a row and column with m(i, j).
it means your [] operator returns a value without an address that cannot be used for assignment. Its straight forward.
What is Vector?
The problem probably starts with what Matrix::operator[]
returns. For the [][] syntax to work, it must return some
sort of proxy, to which the second [] can be applied, and it
will return a reference to the desired element in the matrix.
The usual way of doing this (at least for me) is to define
a "setter" and "getter" in Matrix:
void set( int i, int j, double new_value )
{
myData[ getIndex( i, j ) ] = new_value;
}
double get( int i, int j ) const
{
return myData[ getIndex( i, j ) ];
}
and then make use of two proxies (nested classes in Matrix):
class Proxy2D
{
Matrix* myOwner;
int myIndex1;
int myIndex2;
public:
Proxy2D( Matrix& owner, int index1, int index2 )
: myOwner( &owner )
, myIndex1( index1 )
, myIndex2( index2 )
{
}
void operator=( double new_value ) const
{
myOwner->set( myIndex1, myIndex2, new_value ):
}
operator double() const
{
return myOwner->get( myIndex1, myIndex2 );
}
};
class Proxy1D
{
Matrix* myOwner;
int myIndex;
public:
Proxy1D( Matrix& owner, int index )
: myOwner( &owner )
, myIndex( index )
{
}
Proxy2D operator[]( int index2 ) const
{
return Proxy2D( *myOwner, myIndex, index2 );
}
};
Proxy1D operator[]( int index1 )
{
return Proxy1D( *this, index1 );
}
In practice, you'll want const variants as well, to be returned
by operator[]( int index1 ) const. And of course,
ConstProxy2D won't need the overload for operator=; the
implicit conversion is sufficient.
And in case it isn't obvious, Matrix::getIndex does the bounds
checking, and then calculates the actual index in the underlying
std::vector<double> which contains the data.
Since you return a newly constructed Vector object to represent a column (or row, doesn't really matter), this Vector is responsible to update an entry in the original Matrix instance, which is a little bit tricky but can easily be solved:
You have to implement another VectorRef class which doesn't represent a vector by value but by reference and can thus be used to access the components as lvalues. This means, that it doesn't contain the numbers as values but as reference and takes these references in its constructor. To keep things simple, you can use a pointer which points to the first component (followed by the other components):
class VectorRef {
float *coords;
public:
VectorRef(float *coords) : coords(coords) {}
float & operator[](int i) { return coords[i]; }
};
Then, construct such a "reference object" in the operator[] of the matrix:
VectorRef Matrix::operator[](int i) {
return VectorRef (coords[i]);
}
To use the VectorRef also as a Vector, provide a conversion operator:
// (within VectorRef:)
operator Vector() const { return Vector(coords[0], coords[1], coords[2]); }
This should make things seemless.
Alternatively, if you always access the elements within a matrix and not columns as a whole, just return the column pointer directly in the operator[] of the matrix:
float * Matrix::operator[](int i) {
return coords[i];
}
When writing mat[x][y], this will first access the float pointer with mat[x] and then accesses the y-th element of that column, which is an lvalue.
I am implementing a tridiagonal matrix and I have to be as efficient as possible. Obviously I will only hold the elements that contain data. I overloaded the operator() to act as an indexer into the matrix, but I want this operator to return a reference so that the user can modify the matrix. However, I cannot just return 0; for the non-tridiagonal elements since the zero is not a reference. How do I let the user modify the data on the tridiagonal, but when the operator() is used to inspect a non-tridiagonal element, only return 0 instead of a reference to 0?
below is the related class definition
template <class T>
class tridiagonal
{
public:
tridiagonal();
~tridiagonal();
T& operator()(int i, int j);
const T& operator()(int i, int j) const;
private:
//holds data of just the diagonals
T * m_upper;
T * m_main;
T * m_lower;
};
One trick you can use is to have the non-const operator() (int, int) method return a little helper object. The helper is used to differentiate between assigning into the matrix and just pulling out a value. This lets you have different behavior for the two operations. In particular, you can throw if someone tries to assign into a value that must be zero.
This code at least compiles for me in VC10, but obviously doesn't link.
template <class T>
class tridiagonal
{
public:
// Helper class that let's us tell when the user is
// assigning into the matrix and when they are just
// getting values.
class helper
{
tridiagonal<T> &m_parent;
int m_i, m_j;
public:
helper(tridiagonal<T> &parent, int i, int j)
: m_parent(parent), m_i(i), m_j(j)
{}
// Converts the helper class to the underlying
// matrix value. This doesn't allow assignment.
operator const T & () const {
// Just call the const operator()
const tridiagonal<T> &constParent = m_parent;
return constParent(m_i, m_j);
}
// Assign a value into the matrix.
// This is only called for assignment.
const T & operator= (const T &newVal) {
// If we are pointing off the diagonal, throw
if (abs(m_i - m_j) > 1) {
throw std::exception("Tried to assign to a const matrix element");
}
return m_parent.assign(m_i, m_j, newVal);
}
};
tridiagonal();
~tridiagonal();
helper operator()(int i, int j)
{
return helper(*this, i,j);
}
const T& operator()(int i, int j) const;
private:
T& assign(int i, int j, const T &newVal);
//holds data of just the diagonals
T * m_upper;
T * m_main;
T * m_lower;
};
int main(int argc, const char * argv[])
{
tridiagonal<double> mat;
std::cout << mat(0,0) << std::endl;
const tridiagonal<double> & constMat = mat;
std::cout << mat(2,3) << std::endl;
// Compiles and works
mat(2,3) = 10.0;
// Compiles, but throws at runtime
mat(1, 5) = 20.0;
// Doesn't compile
// constMat(3,3) = 12.0;
return 0;
}
It's been a while since I've done this, so you may find that you need to add a bit more to the helper class, depending on how you use the matrix.
Actually working through this is a good C++ exercise. :)
The issue you have here is an inappropriate interface. If your definition of a matrix is a 2D array of numbers such that every element of the matrix can be individually set, then a sparse, tridiagional matrix is paradoxically not a matrix (just as a square is not a modifiable rectangle - a classic example of inappropriate inheritance that doesn't obey the Liskov Substitution Principle).
In short, you'd be better off changing your interface to suit sparse, tridiagonal matrices rather than trying to hack it to work with the interface you've got. That said, if you must do it this way, then you are probably better off doing two things:
Modifying your const accessor to return T instead of const T& (I'm assuming we're only dealing with matrices of numbers here). Then you can just return 0 for the elements off the diagonal.
Modifying your non-const accessor to return a reference to a dummy element for locations off the diagonal, and crossing your fingers :) Alternatively, you could change the specification to throw in such cases, but that might be a little unfriendly.
One other alternative (short of reworking the interface properly) might be to return proxy objects instead of Ts. The proxy for dummy elements would then throw when you try and set the value using it.
Returning by reference requires that you return a valid object of the specified type. The simplest way to accomplish what you want is to keep a static T object that represents 0, and return it instead.
Alternatively, you could return a pointer.
Just add an extra member representing some dummy value and make sure it always reads as 0.
template<typename T>
class tridiagonal
{
// usual stuff...
T& operator() (int j, int j)
{
// if not explicitly stored, reset to default before returning.
return stored(i,j)? fetch(i,j) : (m_dummy=T());
}
private:
// dummy element used to "reference" elements outside the 3 diagonals.
T m_dummy;
// check if (i,j) is on 3 diagonals.
bool stored (int i, int j) const;
// access element on 3 diagonals. precondition: stored(i,j)==true.
T& fetch (int i, int j);
//holds data of just the diagonals
T * m_upper;
T * m_main;
T * m_lower;
};
Note that technically speaking, someone could trick you as such:
tridiagonal<int> m(4,4);
T * dummy = &m(3,0); // *dummy == 0.
*dummy = 1; // *dummy == 1.
std::cout << *dummy; // prints 1.
But that's not necessarily a problem.
I am writing a template Polynom<T> class where T is the numeric type of its coefficients.
The coefficients of the polynom are stored in an std::vector<T> coefficients, where coefficients[i] corresponds to x^i in a real polynom. (so the powers of x are in increasing order).
It is guaranteed that coefficients vector always contains at least one element. - for a zero polynom it is T().
I want to overload the operator[] to do the following:
The index passed to the operator[] corresponds to the power of X whose coefficient we want to modify / read.
If the user wants to just read the coefficient, it should throw for negative indices, return coefficients.at(i) for indices within the stored range - and reasonably return 0 for all other indices, not throw.
If the user wants to modify the coefficient, it should throw for negative indices, but let user modify all other indices freely, even if the index specified is bigger than or equal to coefficients.size(). So we want to somehow resize the vector.
The main problem I have collided with is as follows:
1.
How do I distinguish between the read case and the write case? One person left me without an explanation but said that writing two versions:
const T& operator[] (int index) const;
T& operator[] (int index);
was insufficient. However, I thought that the compiler would prefer the const version in the read case, won't it?
2.
I want to make sure that no trailing zeros are ever stored in the coefficients vector. So I somehow have to know in advance, "before" I return a mutable T& of my coefficient, what value user wants to assign. And I know that operator[] doesn't receive a second argument.
Obviously, if this value is not zero (not T()), then I have to resize my vector and set the appropriate coefficient to the value passed.
But I cannot do it in advance (before returning a T& from operator[]), because if the value to be assigned is T(), then, provided I resize my coefficients vector in advance, it will eventually have lots of trailing "zeroes".
Of course I can check for trailing zeroes in every other function of the class and remove them in that case. Seems a very weird decision to me, and I want every function to start working in assumption that there are no zeroes at the end of the vector if its size > 1.
Could you please advise me as concrete solution as possible to this problem?
I heard something about writing an inner class implicitly convertible to T& with overloaded operator=, but I lack the details.
Thank you very much in advance!
One option you could try (I haven't tested this):
template<typename T>
class MyRef{
private:
int index;
Polynom<T>*p;
public:
MyRef(int index, Polynom<T>*p) : index(index), p(p) { }
MyRef<T>& operator=(T const&t); //and define these appropriately
T operator T() const;
};
and define:
MyRef<T> operator[](int index){
return MyRef<T>(index, this);
}
This way when you assign a value to the "reference" it should have access to all the needed data in the polynomial, and take the appropriate actions.
I am not familiar enough with your implementation, so I'll instead give an example of a very simple dynamic array that works as follows:
you can read from any int index without concern; elements not previously written to should read off as 0;
when you write to an element past the end of the currently allocated array, it is reallocated, and the newly allocated elements are initialized to 0.
#include <cstdlib>
#include <iostream>
using namespace std;
template<typename T>
class my_array{
private:
T* _data;
int _size;
class my_ref{
private:
int index;
T*& obj;
int&size;
public:
my_ref(T*& obj, int&size, int index)
: index(index), obj(obj), size(size){}
my_ref& operator=(T const& t){
if (index>=size){
obj = (T*)realloc(obj, sizeof(T)*(index+1) );
while (size<=index)
obj[size++]=0;
}
obj[index] = t;
return *this;
}
//edit:this one should allow writing, say, v[1]=v[2]=v[3]=4;
my_ref& operator=(const my_ref&r){
operator=( (T) r);
return *this;
}
operator T() const{
return (index>=size)?0:obj[index];
}
};
public:
my_array() : _data(NULL), _size(0) {}
my_ref operator[](int index){
return my_ref(_data,_size,index);
}
int size() const{ return _size; }
};
int main(){
my_array<int> v;
v[0] = 42;
v[1] = 51;
v[5] = 5; v[5]=6;
v[30] = 18;
v[2] = v[1]+v[5];
v[4] = v[8]+v[1048576]+v[5]+1000;
cout << "allocated elements: " << v.size() << endl;
for (int i=0;i<31;i++)
cout << v[i] << " " << endl;
return 0;
}
It's a very simple example and not very efficient in its current form but it should prove the point.
Eventually you might want to overload operator& to allow things like *(&v[0] + 5) = 42; to work properly. For this example, you could have that operator& gives a my_pointer which defines operator+ to do arithmetic on its index field and return a new my_pointer. Finally, you can overload operator*() to go back to a my_ref.
The solution to this is a proxy class (untested code follows):
template<typename T> class Polynom
{
public:
class IndexProxy;
friend class IndexProxy;
IndexProxy operator[](int);
T operator[](int) const;
// ...
private:
std::vector<T> coefficients;
};
template<typename T> class Polynom<T>::IndexProxy
{
public:
friend class Polynom<T>;
// contrary to convention this assignment does not return an lvalue,
// in order to be able to avoid extending the vector on assignment of 0.0
T operator=(T const& t)
{
if (theIndex >= thePolynom.coefficients.size())
thePolynom.coefficients.resize(theIndex+1);
thePolynom.coefficients[theIndex] = t;
// the assignment might have made the polynom shorter
// by assigning 0 to the top-most coefficient
while (thePolynom.coefficients.back() == T())
thePolynom.coefficients.pop_back();
return t;
}
operator T() const
{
if (theIndex >= thePolynom.coefficients.size())
return 0;
return thePolynom.coefficients[theIndex];
}
private:
IndexProxy(Polynom<T>& p, int i): thePolynom(p), theIndex(i) {}
Polynom<T>& thePolynom;
int theIndex;
}
template<typename T>
Polynom<T>::IndexProxy operator[](int i)
{
if (i < 0) throw whatever;
return IndexProxy(*this, i);
}
template<typename T>
T operator[](int i)
{
if (i<0) throw whatever;
if (i >= coefficients.size()) return T();
return coefficients[i];
}
Obviously the code above is not optimized (especially the assignment operator has clearly room for optimization).
You cannot distinguish between read and write with operator overloads. The best you can do is distinguish between usage in a const setting and a non-const setting, which is what your code snippet does. So:
Polynomial &poly = ...;
poly[i] = 10; // Calls non-const version
int x = poly[i]; // Calls non-const version
const Polynomial &poly = ...;
poly[i] = 10; // Compiler error!
int x = poly[i] // Calls const version
It sounds like the answer to both your questions, therefore, is to have separate set and get functions.
I see two solutions to your problem:
Instead of storing the coefficients in a std::vector<T> store them in a std::map<unsigned int, T>. This way you will ever only store non-zero coefficients. You could create your own std::map-based container that would consume zeros stored into it. This way you also save some storage for polynomials of the form x^n with large n.
Add an inner class that will store an index (power) and coefficient value. You would return a reference to an instance of this inner class from operator[]. The inner class would overwrite operator=. In the overridden operator= you would take the index (power) and coefficient stored in inner class instance and flush them to the std::vector where you store your coefficients.
This is not possible. The only way I can think of is to provide a special member-function for adding new coefficients.
The compiler decides between the const and non-const version by looking at the type of Polynom, and not by checking what kind of operation is performed on the return-value.