tags:

views:

322

answers:

3

I have a need for a "container" that acts like the following. It has 2 subcontainers, called A and B, and I need to be able to iterate over just A, just B, and A and B combined. I don't want to use extra space for redundant data, so I thought of making my own iterator to iterate over A and B combined. What is the easiest way to make your own iterator? Or, what is another way to do this?

EDIT Ultimately, I don't think it was good design. I have redesigned the entire class heirarchy. +1 for refactoring. However, I did solve this problem sufficiently. Here's an abbreviated version of what I did, for reference; it uses boost::filter_iterator. Let T be the type in the container.

enum Flag
{
    A_flag,
    B_flag
};

class T_proxy
{
public:
    T_proxy(const T& t, Flag f) : t_(t), flag_(f) {}
    operator T() const {return t_;}
    Flag flag() const {return flag_;}
    class Compare
    {
    public:
        Compare(Flag f) : matchFlag_(f) {}
        operator() (const T_proxy& tp) {return tp.flag() == matchFlag_;}
    private:
        Flag matchFlag_;
    };
private:
    T t_;
    Flag flag_;
};

class AB_list
{
public:
    typedef T_proxy::Compare Compare;
    typedef vector<T_proxy>::iterator iterator;
    typedef boost::filter_iterator<Compare, iterator> sub_iterator;
    void insert(const T& val, Flag f) {data_.insert(T_proxy(val, f));}
    // other methods...

    // whole sequence
    iterator begin() {return data_.begin();}
    iterator end() {return data_.end();}

    // just A
    sub_iterator begin_A() {return sub_iterator(Compare(A_flag), begin(), end());
    sub_iterator end_A() {return sub_iterator(Compare(A_flag), end(), end());

    // just B is basically the same
private:
    vector<T_proxy> data_;
};


// usage
AB_list mylist;
mylist.insert(T(), A_flag);
for (AB_list::sub_iterator it = mylist.begin_A(); it != mylist.end_A(); ++it)
{
    T temp = *it; // T_proxy is convertible to T
    cout << temp;
}
A: 

Have one container which stores the value you are interested in together with a flag indicating whether it is in A or B.

anon
+7  A: 

I will repost my answer to a similar question. I think this will do what you want.

Use a library like Boost.MultiIndex to do what you want. It scales well and there is a lot less boiler plate code if you want to add new indexes. It is also usually more space and time efficient

typedef multi_index_container<
  Container,
  indexed_by<
    sequenced<>, //gives you a list like interface
    ordered_unique<Container, std::string, &Container::a_value>, //gives you a lookup by name like map
    ordered_unique<Container, std::string, &Container::b_value> //gives you a lookup by name like map
  >
> container;

If you are iterating over one index, you can switch to another index by using the iterator projection concept in the library.

grepsedawk
Boost.MultiIndex doesn't seem to have a way to exclude elements, however.
rlbond
A: 

You could also create a single container containing std::pair<> objects.

Billy3

Billy ONeal