简体   繁体   English

c ++中的“通用”迭代器

[英]“Generic” iterator in c++

I have: 我有:

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

How can I make that function "generic", so it can take any kind of inputiterators ? 如何使该功能“通用”,所以它可以采取任何类型的输入器? I don't really care if it's iterating a deque,a vector or something else, as long as the iterator is iterating Message's. 只要迭代器迭代Message,我就不在乎它是否正在迭代一个deque,一个向量或其他东西。 - is this at all straight forward possible in c++ ? - 这在C ++中是否可以直接进行?

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

usage : 用法:

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

You need to specify the end, otherwise you won't know when to stop! 你需要指定结束,否则你不知道何时停止! It also gives you the flexibility of adding only a subrange of a container. 它还为您提供了仅添加容器子范围的灵活性。

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

Usage: 用法:

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

If you want the compiler to check whether the iterator actually refers to Message objects, you can use a technique like the following. 如果希望编译器检查迭代器是否实际引用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);
}

If you don't want to templatize your add_all_msgs function, you can use adobe::any_iterator : 如果您不想模板化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);

Slightly simpler that the above (in that it leverages existing libraries): 稍微简单一点(上面它利用了现有的库):

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

It's difficult to have dynamic polymorphism with C++-style iterators. 使用C ++风格的迭代器很难实现动态多态。 operator++(int) returns by value, which afaik is intractable: you can't have a virtual member function which returns *this by value without it being sliced. operator++(int)按值返回,afaik是难以处理的:你不能有一个虚拟成员函数,它返回*this by value而不进行切片。

If possible, I recommend using templates as everyone else says. 如果可能的话,我建议像其他人说的那样使用模板。

However if you do need dynamic polymorphism, for example because you can't expose the implementation of add_all_msgs as a template would do, then I think you could pretend to be Java, like 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);
}

I've checked that this compiles, but I haven't tested it and I've never used this design before. 我已经检查过这个编译,但我还没有测试过,我之前从未使用过这个设计。 I also haven't bothered with const-ness - in practice you probably want a const Message &get() const . 我也没有对const-ness感到困扰 - 在实践中你可能想要一个const Message &get() const And at the moment the adaptor has no way of knowing when to stop, but then neither does the code you started with, so I've ignored that too. 目前,适配器无法知道何时停止,但是你开始使用的代码也没有,所以我也忽略了它。 Basically you'd need a hasNext function which compares wrapped against an end iterator supplied to the constructor. 基本上你需要一个hasNext函数来比较wrapped提供给构造函数的end迭代器。

You might be able to do something with a template function and const references, so that the client doesn't have to know about or declare that nasty Adaptor type. 您可以使用模板函数和const引用执行某些操作,以便客户端不必了解或声明该讨厌的适配器类型。

[Edit: come to think of it, it's probably better to have a stub add_all_msgs function template, that wraps its parameter in an Adaptor and then calls real_add_all_msgs . [编辑:想想看,最好有一个存根add_all_msgs函数模板,它将其参数包装在一个Adapter中,然后调用real_add_all_msgs This completely hides the adaptor from the client.] 这完全隐藏了客户端的适配器。]

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM