代码之家  ›  专栏  ›  技术社区  ›  Xavier Nodet

返回“任意类型的输入迭代器”,而不是vector::迭代器或list::迭代器[duplicate]

  •  2
  • Xavier Nodet  · 技术社区  · 17 年前

    假设我想在C++中实现一个数据结构来存储有向图。由于STL容器,圆弧将存储在节点中。我希望用户能够以类似STL的方式迭代节点的弧。

    我的问题是我不想在Node类(实际上是一个抽象基类)中公开我将在concrete类中实际使用的STL容器。因此,我不想让我的方法返回std::list::iterator或std::vector::iterator。。。

    我试过这个:

    class Arc;
    
    typedef std::iterator<std::random_access_iterator_tag, Arc*> ArcIterator;  // Wrong!
    
    class Node {
    public:
      ArcIterator incomingArcsBegin() const {
        return _incomingArcs.begin();
      }
    private:
      std::vector<Arc*> _incomingArcs;
    };
    

    但这是不正确的,因为vector::const_迭代器不能用于创建ArcIterator。那么这个arciditor是什么呢?

    我发现这篇关于 Custom Iterators for the STL 但这没有帮助。我今天一定有点重。。。;)

    10 回复  |  直到 17 年前
        1
  •  8
  •   zvrba    17 年前

    试试这个:

    class Arc;
    class Node {
    private:
      std::vector<Arc*> incoming_;
    public:
      typedef std::vector<Arc*>::iterator iterator;
      iterator incoming_arcs_begin()
      { return incoming_.begin(); }
    };
    

    在剩下的代码中使用Node::iterator。当/如果更改容器,则必须在单个位置更改typedef。(在本例中,可以进一步使用额外的typedef来存储vector。)

    至于const问题,要么将vector的const_迭代器定义为迭代器,要么像vector那样定义双迭代器类型(const和non const版本)。

        2
  •  3
  •   Joaquin M Lopez MunozJoaquin M Lopez Munoz    17 年前

    看看Adobe的 any_iterator :该类使用名为 类型擦除 隐藏在抽象接口后面的欠叶迭代器类型。注意:使用 任何迭代器 由于虚拟调度而导致运行时惩罚。

        3
  •  1
  •   Doug T.    17 年前

    我想应该有一种方法,通过直接STL,类似于你正在尝试做的事情。

    如果不是,你可能会考虑使用 boost's iterator facades and adaptors 您可以在其中定义自己的迭代器或将其他对象调整为迭代器。

        4
  •  1
  •   bk1e    17 年前

    隐藏迭代器基于 std::vector<Arc*>::iterator 您需要一个迭代器类,该类委托给 std::vector<Arc*>::迭代器 . std::iterator 不这样做。

    如果您查看编译器的C++标准库中的头文件,您可能会发现 std::迭代器 它本身并不是很有用,除非您只需要一个定义typedef的类 iterator_category , value_type 等等。

    正如Doug T.在他的回答中提到的,boost库中有一些类可以使编写迭代器变得更容易。特别地, boost::indirect_iterator 如果希望迭代器返回 Arc 当取消引用而不是 Arc* .

        5
  •  1
  •   user150753    16 年前

    考虑使用 Visitor Pattern 以及反转关系:不需要向图结构请求数据容器,而是给图一个函子,让图将该函子应用于其数据。

    visitor模式是图形上常用的模式,请参阅boost关于visitor概念的图形库文档。

        6
  •  0
  •   Greg Rogers    17 年前

    如果您真的不希望该类的客户端知道它在下面使用了一个向量,但仍然希望它们能够以某种方式遍历它,那么您很可能需要创建一个类,将其所有方法转发给std::vector::iterator。

    另一种方法是根据节点下面应该使用的容器类型对节点进行模板化。然后客户明确知道它使用的是什么类型的容器,因为他们告诉他们使用它。

    就我个人而言,我认为将向量封装在用户之外通常是没有意义的,但是仍然提供了它的大部分(甚至一些)接口。它的封装层太薄,无法真正提供任何好处。

        7
  •  0
  •   TonJ    17 年前

    我查看了头文件向量。

    vector<Arc*>::const_iterator
    

    是的typedef

    allocator<Arc*>::const_pointer
    

    那可能是你的ArcIterator吗?比如:

    typedef allocator<Arc*>::const_pointer ArcIterator;
    
        8
  •  0
  •   Luc Touraille    17 年前

    您可以将Node类模板化,并在其中同时定义iterator和const_iterator。

    例如:

    class Arc {};
    
    template<
      template<class T, class U> class Container = std::vector,
      class Allocator = std::allocator<Arc*>
    >
    class Node
    {
      public:
        typedef typename Container<Arc*, Allocator>::iterator ArcIterator;
        typedef typename Container<Arc*, Allocator>::Const_iterator constArcIterator;
    
        constArcIterator incomingArcsBegin() const {
          return _incomingArcs.begin();
        }
    
        ArcIterator incomingArcsBegin() {
          return _incomingArcs.begin();
        }
      private:
        Container<Arc*, Allocator> _incomingArcs;
    };
    

    我没有试过这个代码,但它给了你一个想法。但是,您必须注意,使用ConstArcIterator只会禁止修改指向弧的指针,而不允许修改弧本身(例如通过非const方法)。

        9
  •  0
  •   Dima    17 年前

    C++ 0x将允许你这样做 automatic type determination .

    在新标准中
    for (vector::const_iterator itr = myvec.begin(); itr != myvec.end(); ++itr
    可以用这个代替
    for (auto itr = myvec.begin(); itr != myvec.end(); ++itr)

    同样,您将能够返回任何合适的迭代器,并将其存储在 auto 变量。

    在新标准生效之前,您必须对类进行模板化,或者提供一个抽象接口来访问列表/向量的元素。例如,可以通过在成员变量中存储迭代器来实现,并提供成员函数,如 begin() next() . 当然,这意味着一次只能有一个循环可以安全地遍历元素。

        10
  •  0
  •   Evan Teran    14 年前

    因为 std::vector 保证有连续存储,这样做应该很好:

    class Arc;
    typedef Arc* ArcIterator;
    
    class Node {
    public:
        ArcIterator incomingArcsBegin() const {
            return &_incomingArcs[0]
        }
    
        ArcIterator incomingArcsEnd() const {
            return &_incomingArcs[_incomingArcs.size()]
        }
    private:
        std::vector<Arc*> _incomingArcs;
    };
    

    基本上,指针的功能与随机访问迭代器非常相似,足以替代它们。