«Универсальный» итератор в c ++ - PullRequest
11 голосов
/ 09 июля 2009

у меня есть:

void add_all_msgs(std::deque<Message>::iterator &iter);

Как я могу сделать эту функцию "универсальной", чтобы она могла использовать любые виды inputiterators? Мне все равно, перебирает ли он деку, вектор или что-то еще, пока итератор перебирает сообщения. - это вообще возможно в C ++?

Ответы [ 7 ]

13 голосов
/ 09 июля 2009
template <typename Iterator>
void add_all_messages(Iterator first, Iterator last)

использование:

vector<message> v;
add_all_messages(v.begin(), v.end());

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

6 голосов
/ 09 июля 2009
template<class InputIterator>
void add_all_msgs(InputIterator iter);

Использование:

std::deque<Message> deq;
add_all_msgs(deq.begin());
5 голосов
/ 09 июля 2009

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

template <typename InputIterator, typename ValueType>
struct AddAllMessages { };

template <typename InputIterator>
struct AddAllMessages<InputIterator, Message> {
  static void execute(const InputIterator &it) {
    // ...
  }
};

template <typename InputIterator>
void add_all_msgs(const InputIterator &it) {
  AddAllMessages<InputIterator, 
                 typename std::iterator_traits<InputIterator>::value_type>::execute(it);
}
2 голосов
/ 09 июля 2009

Если вы не хотите шаблонизировать свою функцию add_all_msgs, вы можете использовать adobe :: any_iterator :

typedef adobe::any_iterator<Message, std::input_iterator_tag> any_message_iterator;
void add_all_msgs(any_message_iterator begin, any_message_iterator end);
1 голос
/ 09 июля 2009

Трудно иметь динамический полиморфизм с итераторами в стиле C ++. operator++(int) возвращает по значению, что на самом деле сложно: у вас не может быть виртуальной функции-члена, которая возвращает *this по значению без ее нарезки.

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

Однако если вам нужен динамический полиморфизм, например, потому что вы не можете представить реализацию add_all_msgs как шаблон, то я думаю, что вы могли бы притвориться Java, например:

struct MessageIterator {
    virtual Message &get() = 0;
    virtual void next() = 0;
    // add more functions if you need more than a Forward Iterator.
    virtual ~MessageIterator() { };  // Not currently needed, but best be safe
};

// implementation elsewhere. Uses get() and next() instead of * and ++
void add_all_msgs(MessageIterator &it);

template <typename T>
struct Adaptor : public MessageIterator {
    typename T::iterator wrapped;
    Adaptor(typename T::iterator w) : wrapped(w) { }
    virtual Message &get() {
        return *wrapped;
    }
    virtual void next() {
        ++wrapped;
    }
};

int main() {
    std::deque<Message> v;
    Adaptor<std::deque<Message> > a(v.begin());
    add_all_msgs(a);
}

Я проверил, что это компилируется, но я не проверял и никогда раньше не использовал этот дизайн. Я также не беспокоился о константности - на практике вы, вероятно, хотите const Message &get() const. И в данный момент у адаптера нет возможности узнать, когда остановиться, но также и код, с которого вы начали, так что я тоже проигнорировал это. В основном вам понадобится функция hasNext, которая сравнивает wrapped с конечным итератором, предоставленным конструктору.

Возможно, вы сможете что-то сделать с помощью функции шаблона и ссылок на const, чтобы клиенту не приходилось знать или объявлять этот неприятный тип адаптера.

[Edit: если подумать, возможно, лучше иметь шаблон функции-заглушки add_all_msgs, который оборачивает свой параметр в адаптере и затем вызывает real_add_all_msgs. Это полностью скрывает адаптер от клиента.]

1 голос
/ 09 июля 2009

Немного проще, чем выше (в том смысле, что он использует существующие библиотеки):

#include <boost/static_assert.hpp> // or use C++0x static_assert
#include <boost/type_traits/is_same.hpp>

template <typename InputIterator>
void add_all_msgs( InputIterator it ) {
    BOOST_STATIC_ASSERT(( boost::is_same<
        typename std::iterator_traits<InputIterator>::value_type,
        Message>::value ));
    // ...
0 голосов
/ 09 июля 2009
#include <deque>
#include <vector>
#include <list>
#include <string>
using namespace std;

template<typename T>
void add_all_msgs(T &iter)
{

}

int _tmain(int argc, _TCHAR* argv[])
{
    std::deque<string>::iterator it1;
    std::vector<string>::iterator it2;
    std::list<string>::iterator it3;

    add_all_msgs(it1);
    add_all_msgs(it2);
    add_all_msgs(it3);


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