tags:

views:

219

answers:

1

I basically want to have a base container class which can return a generic iterator that can be used to traverse an instance of the container class, without needing to specify iterator templates. I think I cannot implement the base container over a class template, which would then require a traversal algorithm based on template classes which are not known in advance. The base container can be inherited and implemented using any (custom or standard) container type/implementation within. Here are some code samples to make it clear:

struct MyObject {
  int myInt;
}

// an abstract container
class BaseContainer {
public:
  virtual void insertMyObject(MyObject& obj) = 0;
  virtual iterator getFirst(); // the iterator type is for demonstration purposes only
  virtual iterator getLast();  // the iterator type is for demonstration purposes only
}

// Sample container class that uses a std::vector instance to manage objects
class BaseContainer_Vector : public BaseContainer {
public:
  void insertMyObject(MyObject& obj); // e.g. just pushes back to the vector
  iterator getFirst(); // needs to override the iterator?
  iterator getLast();  // needs to override the iterator?
private:
  std::vector<MyObject> objectContainer;
}

I will then have a list of container objects, and I want to iterate over both these containers and the objects stored.

std::vector<MyContainer*> containers;
for(int i=0 ; i<containers.size() ; i++){
  iterator i    = containers[i]->getFirst();
  iterator iend = containers[i]->getLast();
  for(; i != iend ; i++) {
    std::cout << (*i).myInt << std::endl;
  }
}

I further would like to have support for boost foreach macro statement. It supports extensions as long as range_begin and range_end functions are properly. But, the example in boost doc uses std::string::iterator as return type, while what I need is a generic iterator class and I could not yet figure out how to do that as well.

std::vector<MyContainer*> containers;
for(int i=0 ; i<containers.size() ; i++){
  BOOST_FOREACH(MyObject obj, *(containers[i])) {
    std::cout << obj.myInt << std::endl;
  }
}

I think I can define my own iterator class, then each class that extends BaseContainer should define their own iterator extending that basic iterator. Yet, I would prefer to use standard iterators (stl or boost) to support this structure, rather that writing my own iterators. I guess this approach will work, but I am open to comments regarding its efficiency.

Is there a feasible approach that can solve this problem elegantly? Or am I missing a simple point which can solve this problem without any pain?

A similar question can be found here, but the proposed solutions seem a bit complex for my needs, and the requirements differ as far as I can understand.

+1  A: 

It's gonna be complicated.

As already stated, first you need your iterators to have value semantic because since they are usually copied around otherwise it would result in object slicing.

class BaseContainer
{
protected:
  class BaseIteratorImpl; // Abstract class, for the interface

public:
  class iterator
  {
  public:
    iterator(const BaseIteratorImpl& impl);
  private:
    BaseIteratorImpl* m_impl;
  };

  iterator begin();
  iterator end();
}; // BaseContainer

Then, BaseIterator forwards all methods to m_impl.

This way you achieve value semantic syntax with a polymorphic core.

Obviously, you'll have to handle deep-copy semantics and proper destruction.

Some notes:

  • publish both an iterator and a const_iterator class
  • name your methods empty, size, begin, end etc... for compatibility with STL algorithms

You can check SGI Iterators for help about the Concepts and operations your operators should support for maximum compatibility.

Matthieu M.
Thank you for the response, I will now try to implement a custom iterator based on your approach. The user will eventually need to define a custom increment, begin, end operations for the container(s) that are internally used. I will report back on the results hopefully soon :)
tersyon
I inherited the public iterator class you proposed from std::iterator<std::forward_iterator_tag,MyObject>, and so could make it work with BOOST_FOREACH as well :) Thanks for pointing in the right direction, it works as I wanted it to be, with minimal code overhead :)
tersyon
It's always a pleasure to be of help to people with interesting problems... or at least problems I'm interested in :)
Matthieu M.