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

时间:2009-07-09 13:53:19

标签: c++ stl iterator

我有:

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

如何使该功能“通用”,因此可以采用任何类型的输入器?只要迭代器迭代Message,我就不在乎它是否正在迭代一个deque,一个向量或其他东西。 - 这在C ++中是否可以直接进行?

7 个答案:

答案 0 :(得分:13)

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

用法:

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

您需要指定结束,否则您将不知道何时停止!它还为您提供了仅添加容器子范围的灵活性。

答案 1 :(得分:6)

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

用法:

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

答案 2 :(得分:5)

如果希望编译器检查迭代器是否实际引用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);
}

答案 3 :(得分:2)

如果您不想模板化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);

答案 4 :(得分:1)

上述内容稍微简单一点(因为它利用了现有的库):

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

答案 5 :(得分:1)

使用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与提供给构造函数的结束迭代器进行比较。

您可以使用模板函数和const引用执行某些操作,以便客户端不必了解或声明该讨厌的适配器类型。

[编辑:想想看,最好有一个存根add_all_msgs函数模板,它将其参数包装在一个Adapter中,然后调用real_add_all_msgs。这完全隐藏了客户端的适配器。]

答案 6 :(得分:0)

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