Friday, February 09, 2007

Functors with state - 1

Some time back, I had come across a small problem to which I tried writing out a solution. The problem and the solution both were simple but there was something that I learnt that can mess your code and you will have little idea about it.

The problem was to split a vector of integers into 2 vectors of integers. The first one would contain the elements at odd indexes and second one would contain the elements at the even indexes.

Here is a solution that I had provided:

[CODE]

#include<algorithm>
#include<vector>
#include<iostream>

template<typename T>
struct IsEvenIndex{
               private:
                               static typename std::vector<T>::size_type index;
                               std::vector<T>& refVec;
               public:
                               bool operator()(const T& t) const{
                                               if (index%2==0){
                                                               ++index;
                                                               refVec.push_back(t);
                                                               return true;
                                               }else{
                                                               ++index;
                                                               return false;
                                               }
                               }
                               IsEvenIndex(std::vector<T>& vec) : refVec(vec){}
};

template<typename T>
typename std::vector<T>::size_type IsEvenIndex<T>::index=0;

template<typename T>
void PrintVector(const std::vector<T>& t){
               std::cout << std::endl << "Printing vector contents" << std::endl;
               for(typename std::vector<T>::size_type i=0; i<t.size(); ++i){
                               std::cout << t[i] << '\t';
               }
               std::cout << std::endl << std::endl;
}

int main(){
               std::vector<int> myintVector;
               std::vector<int> myotherintVector;
               for(int i=1; i<=10; ++i){
                       myintVector.push_back(i*10);
               }
               PrintVector(myintVector);
               std::vector<int>::iterator itend = std::remove_if(myintVector.begin(), myintVector.end(), IsEvenIndex<int>(myotherintVector));
               myintVector.erase(itend, myintVector.end());
               PrintVector(myintVector);
               PrintVector(myotherintVector);
}


The inlined comments explain the things being done quite clearly. All is fine and well and we get the output as expected. Here is the sample outout that I got:

[OUTPUT]

Printing vector contents
10 20 30 40 50 60 70 80 90 100
Printing vector contents
20 40 60 80 100
Printing vector contents
10 30 50 70 90

There are better ways to do this, of course. The easiest would be to iterate the initially populated vector and alternately keep populating two other vectors to contain the result-sets.

There can be improvements to the functor as well. By removing the push_back from the functor to an insert function that populates the 2nd vector from the removed elements from first vector, followed by an erase call.

But let's not deviate. There is a point of concern in the above code that will lead you to the point of discussion that I wanted to concentrate on.

To be continued in Functors with state - 2. Later!

No comments: