Ответ 1
template<class InputIterator>
void add_all_msgs(InputIterator iter);
Использование:
std::deque<Message> deq;
add_all_msgs(deq.begin());
У меня есть:
void add_all_msgs(std::deque<Message>::iterator &iter);
Как я могу сделать эту функцию "generic", чтобы она могла принимать любые типы ввода? Меня не волнует, если он перебирает deque, вектор или что-то еще, до тех пор, пока итератор повторяет сообщение. - возможно ли это прямо в С++?
template<class InputIterator>
void add_all_msgs(InputIterator iter);
Использование:
std::deque<Message> deq;
add_all_msgs(deq.begin());
template <typename Iterator>
void add_all_messages(Iterator first, Iterator last)
использование:
vector<message> v;
add_all_messages(v.begin(), v.end());
Вам нужно указать конец, иначе вы не будете знать, когда остановиться! Это также дает вам гибкость добавления только поддиапазона контейнера.
Если вы хотите, чтобы компилятор проверял, действительно ли итератор ссылается на объекты 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);
}
Если вы не хотите 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);
Чуть проще, чем выше (в том, что он использует существующие библиотеки):
#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 ));
// ...
Сложно иметь динамический полиморфизм с итераторами стиля 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
. Это полностью скрывает адаптер от клиента.]
#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;
}