I was trying to learn writing stl like iterators, for that I wrote a simple circular array and added an iterator in it. Please look at the bottom of the code to see the problem.
template<typename T, int N>
class RingQueue{
T * _marray;
int _mbegin;
int _msize;
public:
RingQueue(){
_marray = new T[N];
_mbegin = 0;
_msize= 0;
}
void push_back(const T& val){
if(_msize!=N){
_marray[(_mbegin+_msize)%N] = val;
_msize++;
}
else
throw "Queue Full";
}
T pop_front(){
if(_msize!=0){
T&val = _marray[_mbegin];
_mbegin = (_mbegin+1)%N;
_msize--;
return val;
}
else
throw "Queue Empty";
}
class iterator{
RingQueue<T,N>* _container;
int _idx;
public:
iterator(RingQueue<T,N>* container,int idx):_container(container){
_idx = idx;
}
bool operator==(iterator &rhs){
return (this->_container==rhs._container && this->_idx == rhs._idx);
}
bool operator!=(iterator &rhs){
return !(*this==rhs);
}
T operator*(){
if(_container->_msize>0&&_idx<_container->_msize){
return _container->_marray[(_container->_mbegin+_idx)%N];
}
}
iterator& operator++(){
if(_container->_msize ==0){
*this = _container->end();
return *this;
}
if(_idx==_container->_msize){
*this = _container->end();
return *this;
}
_idx++;
return *this;
}
};
iterator begin(){
return iterator(this,0);
}
iterator end(){
return iterator(this,_msize);
}
};
int current=0;
int gen(){
return current++;
}
int curr_op=0;
int operation(){
return 2*(curr_op++&1)-1;
}
int main(){
RingQueue<int,10> ring;
vector<int> v(9),op(9);
generate(v.begin(),v.end(),gen);
random_shuffle(v.begin(),v.end());
copy(v.begin(),v.end(),ostream_iterator<int>(cout," "));
cout<<endl;
generate(op.begin(),op.end(),operation);
random_shuffle(op.begin(),op.end());
// copy(op.begin(),op.end(),ostream_iterator<int>(cout," "));
cout<<endl;
for(vector<int>::iterator itv = v.begin();itv!=v.end();itv++){
try{
ring.push_back(*itv);
}catch(const char * e){
cout<<*itv<<e<<endl;
}
}
//works
RingQueue<int,10>::iterator ite = ring.end();
for(RingQueue<int,10>::iterator it = ring.begin(); it!=ite; ++it){
cout<<*it<<endl;
}
// doesn't work
for(RingQueue<int,10>::iterator it = ring.begin(); it!=ring.end(); ++it){
cout<<*it<<endl;
}
return 0;
}
When I compile the doesn't work part, g++ dumps the following error
ringqueue.cpp: In function ‘int main()’:
ringqueue.cpp:112: error: no match for ‘operator!=’ in ‘it != ring.RingQueue<T, N>::end [with T = int, int N = 10]()’
ringqueue.cpp:48: note: candidates are: bool RingQueue<T, N>::iterator::operator!=(RingQueue<T, N>::iterator&) [with T = int, int N = 10]
the works part compiles seamlessly, when compiled without doesn't work part. Can somebody explain me what's wrong.
I think the issue is in these lines:
bool operator==(iterator &rhs){
return (this->_container==rhs._container && this->_idx == rhs._idx);
}
bool operator!=(iterator &rhs){
return !(*this==rhs);
}
The problem here is that these functions take in lvalue references to their arguments. This means that if you try passing an rvalue (for example, a temporary object returned from a function) into these operators, you will get a compile-time error because references cannot bind to temporaries. To fix this, either change the arguments to be const references:
bool operator==(const iterator &rhs){
return (this->_container==rhs._container && this->_idx == rhs._idx);
}
bool operator!=(const iterator &rhs){
return !(*this==rhs);
}
Since const references can bind to temporaries, or have them take their arguments by value:
bool operator==(iterator rhs){
return (this->_container==rhs._container && this->_idx == rhs._idx);
}
bool operator!=(iterator rhs){
return !(*this==rhs);
}
Whichever choice you make, you should probably mark these functions const
because they don't mutate the receiver object.
Hope this helps!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With