Search code examples
c++iteratornested-class

Design operator++ for iterating over certain elements of a multimap


I have the following class declaration:

class Dictionnary{
  private:
    map< int,list<string> > data;
  public:
    bool isPrime();
    class prime_iterator{
      private:
        map< int,list<string> >::iterator it;
      public:
        iterator(){}
        prime_iterator & operator++(){
          ++it;
            while(it != data.end() && !isPrime(it->first)){
            ++it;
          }
          return it;
        }
        ...
};

which is intended to provide an iterator over prime keys of a map<int,list<string>>. I'm not sure operator++ is well implemented.

First, is it a good design to do it != data.end()accessing the outer class? Second, is operator++ returning the right thing or should return only prime_iterator?. Also, can you think about any better solution?


Solution

  • My advice is to always try to find solution elsewhere - if not found - then only create by yourself:

    You can use boost::fiter_iterator

    For your case it would look in this way:

    #include <boost/iterator/filter_iterator.hpp>
    
    using DataMap = std::map<int, std::list<std::string>>;
    struct is_prime_number {
      bool operator()(const DataMap::value_type& x) { return x.first % 2 == 0; }
    }; // I know this is just is_even - not is_prime :D
    
    using DataMapPrimeIter = boost::filter_iterator<is_prime_number, DataMap::iterator>;
    inline DataMapPrimeIter only_prime_begin(DataMap& dataMap)
    {
        return boost::make_filter_iterator<is_prime_number>(dataMap.begin(), dataMap.end());
    }
    inline DataMapPrimeIter only_prime_end(DataMap& dataMap)
    {
        return boost::make_filter_iterator<is_prime_number>(dataMap.end(), dataMap.end());
    }
    

    And usage:

    int main()
    {
        DataMap dataMap{{1,{"A","B"}}, {2,{"C", "D", "E"}}};
        for (auto i = only_prime_begin(dataMap), end = only_prime_end(dataMap); i != end; ++i)
        {
            std::cout << i->first << i->second.front() << std::endl;
        }
    }
    

    If you want to have your own implementation, or you cannot use boost in your project - then look at boost implementation - it is for free to look at...