"Общий" итератор в С++

У меня есть:

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

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

Ответ 1

template<class InputIterator>
void add_all_msgs(InputIterator iter);

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

std::deque<Message> deq;
add_all_msgs(deq.begin());

Ответ 2

template <typename Iterator>
void add_all_messages(Iterator first, Iterator last)

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

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

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

Ответ 3

Если вы хотите, чтобы компилятор проверял, действительно ли итератор ссылается на объекты 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);
}

Ответ 4

Если вы не хотите templatize функции 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);

Ответ 5

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

#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 ));
    // ...

Ответ 6

Сложно иметь динамический полиморфизм с итераторами стиля C++. operator++(int) возвращает по значению, что afaik не поддается решению: у вас не может быть виртуальной функции-члена, которая возвращает *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 с конечным итератором, предоставленным конструктору.

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

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

Ответ 7

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