代码之家  ›  专栏  ›  技术社区  ›  nos

C++中的“泛型”迭代器

  •  11
  • nos  · 技术社区  · 16 年前

    我有:

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

    我怎样才能使这个函数成为“通用的”,这样它就可以接受任何类型的输入器?我真的不关心它是在迭代一个DIGO,一个向量或者别的什么东西,只要迭代器正在迭代消息。

    7 回复  |  直到 13 年前
        1
  •  6
  •   Naveen    16 年前
    template<class InputIterator>
    void add_all_msgs(InputIterator iter);
    

    用途:

    std::deque<Message> deq;
    add_all_msgs(deq.begin());
    
        2
  •  13
  •   Edouard A.    16 年前
    template <typename Iterator>
    void add_all_messages(Iterator first, Iterator last)
    

    用途:

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

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

        3
  •  5
  •   Paolo Capriotti    16 年前

    如果希望编译器检查迭代器是否实际引用 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
  •  2
  •   Greg Rogers    16 年前

    如果不想模板化“全部添加”功能,可以使用 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
  •  1
  •   Steve Jessop    16 年前

    使用C++类迭代器有动态多态性是很困难的。 operator++(int) 按值返回,Afaik很难处理:不能有返回的虚拟成员函数 *this 按价值计算,而不被分割。

    如果可能的话,我建议像其他人说的那样使用模板。

    但是,如果您确实需要动态多态性,例如,因为您不能将AddiaLaysMSGS的实现暴露为模板,那么我认为您可以假装为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 针对提供给构造函数的结束迭代器。

    您可以使用模板函数和常量引用来做一些事情,这样客户机就不必知道或声明这种讨厌的适配器类型。

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

        6
  •  1
  •   Marc Mutz - mmutz    13 年前

    稍微简单一点,上面的(它利用了现有的库):

    #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 ));
        // ...
    
        7
  •  0
  •   Indy9000    16 年前
    #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;
    }