Overloading Operator [] to Accept Range - c++

I would like to overload operator[] to accept 2 int's, so that the user will be able to specify a range of indices like so:
MyClass[1:5]
I tried this:
void operator[](const int, const int);
with the hope that I would be able to use it with comma:
MyClass[1,5]
but I get a compiler error:
too many parameters for this operator function
Is there a way that I can achieve such behaviour?
Thanks
EDIT:
I was hoping the operator would do something like so:
struct MyClass
{
vector<std::string> data;
void operator[] (const int start, const int end)
{
for(int index = start; index <= end; index++)
{
cout << data[index] << '\n';
}
}
};

It's impossible.
You need to pick a different syntax, e.g:
MyClass(1,5) - overloaded operator().
MyClass.foo(1,5) - a member function.
MyClass[{1,5}] - overloaded operator[] with a parameter of class type, which has a constructor that accepts 2 parameters.

You can use for example std::initializer_list as an argument.
For example
T & operator []( const std::initializer_list<size_t> & );
const T & operator []( const std::initializer_list<size_t> & ) const;
or just like
T operator []( const std::initializer_list<size_t> & ) const;

Related

How to overload [] operator for mpf_t array in a template class in C++?

I am trying to develop a custom class in C++ which would contain a mpfr_t array.
The problem is, I do not know how to overload the [] operator to access array elements.
See the code below:
template <const unsigned int N>
class MyClass<mpfr_t, N> {
private:
mpfr_t array[N];
public:
mpfr_t& operator[] (const unsigned int i) const {
assert(0 <= i && i < N);
return array[i];
The problem with the code above is that I cannot use const and return a reference; as this would allow for potential value modification. What is usually done in such cases is that people write two versions of []: one const for constant class instances returning a value (not a reference) and another non-const which returns the reference. However, I cannot return mpfr_t type - this is simply not allowed by the library design:
error: function cannot return array type 'mpfr_t' (aka '__mpfr_struct [1]')
I realise that the problem stems from wrapping a C-dedicated code into strictly C++ mechanism of operator overloading, but I wonder if there is any hack around it?
You can implement the const version of operator[] by returning a const reference, instead of a non-const one (as you do in the current version):
//-----vvvvvvv-----------------------------------vvvvv--
mpfr_t const & operator[] (const unsigned int i) const {
assert(0 <= i && i < N);
return array[i];
}
Note that you can still have the non-const overload as well:
mpfr_t & operator[] (const unsigned int i) {
// ...
The first overload will be chosen if your MyClass object is const.

Is this a bug in STL? Why do we need operator overloading in this Structure?

I came across this code for Equal_range, and being very new to C++, it is not clear to me why we need to overload the operator even though we have created a new compare function.
Moreover, could we have used:
bool compare( const S& s, const S& s2 )
{
return s.number < s2.number;
}
instead.
#include <algorithm>
#include <vector>
#include <iostream>
struct S
{
int number;
char name;
S ( int number, char name )
: number ( number ), name ( name )
{}
// only the number is relevant with this comparison
bool operator< ( const S& s ) const
{
return number < s.number;
}
};
struct Comp
{
bool operator() ( const S& s, int i )
{
return s.number < i;
}
bool operator() ( int i, const S& s )
{
return i < s.number;
}
};
int main()
{
// note: not ordered, only partitioned w.r.t. S defined below
std::vector<S> vec = { {1,'A'}, {2,'B'}, {2,'C'}, {2,'D'}, {4,'G'}, {3,'F'} };
auto p = std::equal_range(vec.begin(),vec.end(),2,Comp());
for ( auto i = p.first; i != p.second; ++i )
std::cout << i->name << ' ';
}
EDIT: The link to the code is http://en.cppreference.com/w/cpp/algorithm/equal_range
I think this is a bug in your STL implementation. The C++ standard explicitly states it will not call operator< in this case:
The elements are compared using operator< for the first version, and
comp for the second. Two elements, a and b are considered equivalent
if (!(a<b) && !(b<a)) or if (!comp(a,b) && !comp(b,a)).
"First version" refers to the version where no comparison class is provided. "second" refers to the version you used.
I tried this out on VS2013 but it doesn't even compile. The error is:
error C2664: 'bool Comp::operator ()(const S &,int)' : cannot convert
argument 1 from 'S' to 'int'
Unfortunately, the error is deep down inside Microsoft's obfuscated STL implementation. Why would it call operator()(const S&, int) instead of operator()(int, const S&) ?
So I think Visual Studio's STL implementation is wrong. And if your compiler requires it, I think its STL is also wrong. I wonder if they just never tested this where the third argument is not the same type as what is returned by the iterator.
I would love to hear other people's thoughts on this.
In your example code, your various methods of comparing all do different things; the operator< overload allows you to compare an S with another S, where as the Comp struct allows you to compare an S with an int and vise-versa.
If you read the documentation for equal_range
The elements are compared using operator< for the first version, and
comp for the second
You see that you need to be able to do both a[n] < a[i] and comp(a[n], val), the first to compare items in the list to other items in the list, and the second to be able to compare items in the list to the val parameter of the equal_range call. Hence why you need both an operator overload and a comparison method.

Using normal and overloaded operator at the same time

I have a class and i overloaded [ operator to use in main. But the problem here is; somewhere in the class in another function. i want to use [ operator like the old style. How can i use them both or how can i modify my overloaded [ parameter ?
Here is overloading part.
T &operator[](int i)
{
if (i < 0 || i >= ArithmeticVector<T>::size())
throw std::string("Out of bounds!"); //throw std::out_of_range;
else
return data[i];
};
And here is another function i want to use;
friend ArithmeticVector<T> operator /(const ArithmeticVector<T>& v1, const ArithmeticVector<T>& v2 )
{
/*Do quick size check on vectors before proceeding*/
ArithmeticVector<T> result(v1.size());
for (unsigned int i = 0; i < result.size(); ++i)
{
result[i]=v1[i]/v2[i];
}
return result;
};
I get an error like error C2678: binary '[' : no operator found which takes a left-hand operand of type 'const ArithmeticVector'
The problem is with this line.
result[i]=v1[i]/v2[i];
overloaded operator didn't like it :/
I can't understand, what do you mean by I want to use [] operator like the old style, but you should overload operator[] for const version too:
const T& operator[](int i) const
{
// ...
}
v1 and v2 non-modifiable here, they can't call non-const methods.
You need to overload the access operator for const objects as well, because the r.h.s of the expression result[i] = v1[1] / v2 [i] will evaluate to:
v1.operator[](i) / v2.operator[](i)
and both v1 and v2 are of type const ArithmeticVector<T>& which means that the compiler will try to find the operator[](int) const for both of them (they are constant objects). When you overload the operator for const as advised in the answer above, you can re-use the code in the const operator and just call the operator in the non-const operator by casting away constness of the object. That way you don't have to think about what you implemented in one operator and port it to another, and you don't have to debug your code at two places. Here is the model of your problem (I don't have your implementation of ArithmeticVector, so you have to use the parts of it for your stuff):
template<typename T>
class ArithmeticVector;
template<typename T>
ArithmeticVector<T> operator / (
const ArithmeticVector<T>& v1,
const ArithmeticVector<T>& v2
);
template<typename T>
class ArithmeticVector
{
public:
// Your declaration
T& operator[](int i)
{
// Casting away constness allows code re-use.
return const_cast<ArithmeticVector&>(*this).operator[](i);
}
// Const declaration:
T& operator[](int i) const
{
// Put your operator code here.
}
friend ArithmeticVector<T> operator / <> (
const ArithmeticVector<T>& v1,
const ArithmeticVector<T>& v2
);
};
template<typename T>
ArithmeticVector<T> operator / (
const ArithmeticVector<T>& v1,
const ArithmeticVector<T>& v2
)
{
//ArithmeticVector<T> result(v1.size());
ArithmeticVector<T> result;
result[0]=v1[0]/v2[0];
return result;
};
int main(int argc, const char *argv[])
{
ArithmeticVector<int> v1, v2, v3;
v1 = v2 / v3;
return 0;
}
There is a great book of Scott Meyers "Effective C++" and there you can read a great description on constness of objects and access operators. There is an answer on SO, that talks about this.
You need to also take care to avoid a Floating Point Exception (division by zero), or SIGFPE, which will happen when v3[i] == 0, which you can do either by stabilizing the result (you loose accuracy):
result[i] = v1[i] / (v2[I] + 1e-15)
or you introduce a test which slows down the divison significantly (like an if testing if v2[i] == 0).

Two square bracket overloading

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;

compare function for upper_bound / lower_bound

I want to find the first item in a sorted vector that has a field less than some value x.
I need to supply a compare function that compares 'x' with the internal value in MyClass but I can't work out the function declaration.
Can't I simply overload '<' but how do I do this when the args are '&MyClass' and 'float' ?
float x;
std::vector< MyClass >::iterator last = std::upper_bound(myClass.begin(),myClass.end(),x);
What function did you pass to the sort algorithm? You should be able to use the same one for upper_bound and lower_bound.
The easiest way to make the comparison work is to create a dummy object with the key field set to your search value. Then the comparison will always be between like objects.
Edit: If for some reason you can't obtain a dummy object with the proper comparison value, then you can create a comparison functor. The functor can provide three overloads for operator() :
struct MyClassLessThan
{
bool operator() (const MyClass & left, const MyClass & right)
{
return left.key < right.key;
}
bool operator() (const MyClass & left, float right)
{
return left.key < right;
}
bool operator() (float left, const MyClass & right)
{
return left < right.key;
}
};
As you can see, that's the long way to go about it.
You can further improve Mark's solution by creating a static instance of MyClassLessThan in MyClass
class CMyClass
{
static struct _CompareFloatField
{
bool operator() (const MyClass & left, float right) //...
// ...
} CompareFloatField;
};
This way you can call lower_bound in the following way:
std::lower_bound(coll.begin(), coll.end(), target, CMyClass::CompareFloatField);
This makes it a bit more readable
Pass a lambda function to upper_bound
float x;
MyClass target;
target.x_ = x;
std::vector< MyClass >::iterator last =
std::upper_bound(myClass.begin(),myClass.end(),target,
[](const MyClass& a, const MyClass& b){return a.x_ < b.x_;});
I think what you need is std::bind2nd(std::less<MyClass>(), x). But, of course, the operator< must be defined for MyClass.
Edit: oh and I think you will need a constructor for MyClass that accepts only a float so that it can be implicitly converted. However, there might be a better way to do this.