Создайте итератор c ++, который проходит через 2 контейнера - PullRequest
3 голосов
/ 23 мая 2009

Мне нужен «контейнер», который действует следующим образом. У него есть 2 подконтейнера, называемых A и B, и мне нужно иметь возможность перебирать только A, только B, и A и B вместе взятые. Я не хочу использовать дополнительное пространство для избыточных данных, поэтому я подумал о том, чтобы создать свой собственный итератор для перебора A и B вместе. Какой самый простой способ сделать свой собственный итератор? Или как еще это сделать?

РЕДАКТИРОВАТЬ В конечном счете, я не думаю, что это был хороший дизайн. Я перепроектировал весь класс heirarchy. +1 за рефакторинг. Тем не менее, я решил эту проблему достаточно. Вот сокращенная версия того, что я сделал, для справки; он использует boost :: filter_iterator. Пусть T будет типом в контейнере.

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;
}

Ответы [ 3 ]

7 голосов
/ 23 мая 2009

Я отправлю свой ответ на аналогичный вопрос. Я думаю, что это будет делать то, что вы хотите.

Используйте библиотеку типа Boost.MultiIndex , чтобы делать то, что вы хотите. Он хорошо масштабируется, и если вы хотите добавить новые индексы, кода котельной плиты будет намного меньше. Это также обычно более эффективное пространство и время

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;

Если вы выполняете итерацию по одному индексу, вы можете переключиться на другой индекс, используя концепцию проекции итератора в библиотеке.

0 голосов
/ 23 мая 2009

Вы также можете создать один контейнер, содержащий объекты std :: pair <>.

Billy3

0 голосов
/ 23 мая 2009

Имеется один контейнер, в котором хранится интересующее вас значение вместе с флагом, указывающим, находится ли он в A или B.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...