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

发布于 2024-07-26 18:13:27 字数 199 浏览 2 评论 0原文

我有:

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

如何使该函数“通用”,以便它可以采用任何类型的输入迭代器? 我并不关心它是在迭代双端队列、向量还是其他东西,只要迭代器在迭代消息即可。 - 这在 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. - is this at all straight forward possible in c++ ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

久光 2024-08-02 18:13:27
template <typename Iterator>
void add_all_messages(Iterator first, Iterator last)

用法 :

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

需要指定结束,否则不知道什么时候停止! 它还使您可以灵活地仅添加容器的子范围。

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.

薯片软お妹 2024-08-02 18:13:27
template<class InputIterator>
void add_all_msgs(InputIterator iter);

用法:

std::deque<Message> deq;
add_all_msgs(deq.begin());
template<class InputIterator>
void add_all_msgs(InputIterator iter);

Usage:

std::deque<Message> deq;
add_all_msgs(deq.begin());
尐籹人 2024-08-02 18:13:27

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

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);
}
温柔戏命师 2024-08-02 18:13:27

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

If you don't want to templatize your add_all_msgs function, you can use 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);
兮颜 2024-08-02 18:13:27

使用 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 性 - 实际上你可能需要一个 const Message &get() const 。 目前适配器无法知道何时停止,但是您开始使用的代码也不知道,所以我也忽略了这一点。 基本上,您需要一个 hasNext 函数,它将 wrapped 与提供给构造函数的结束迭代器进行比较。

您也许可以使用模板函数和常量引用做一些事情,这样客户端就不必了解或声明那个令人讨厌的适配器类型。

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

It's difficult to have dynamic polymorphism with C++-style iterators. 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.

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:

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. 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.

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.

[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. This completely hides the adaptor from the client.]

苦行僧 2024-08-02 18:13:27

比上面的稍微简单一些(因为它利用了现有的库):

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

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 ));
    // ...
情话难免假 2024-08-02 18:13:27
#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;
}
#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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文