返回“任何类型的输入迭代器” 而不是向量::迭代器或列表::迭代器
假设我想用 C++ 实现一个数据结构来存储定向图。 由于 STL 容器,弧将存储在节点中。 我希望用户能够以类似 STL 的方式迭代节点的弧。
我遇到的问题是,我不想在 Node 类(实际上是一个抽象基类)中公开我将在具体类中实际使用的 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_iterator创建一个 ArcIterator。 那么这个 ArcIterator 会是什么?
我找到了这篇关于 STL 的自定义迭代器 的论文,但它没有帮助。 我今天一定有点重...;)
Suppose I want to implement in C++ a data-structure to store oriented graphs. Arcs will be stored in Nodes thanks to STL containers. I'd like users to be able to iterate over the arcs of a node, in an STL-like way.
The issue I have is that I don't want to expose in the Node class (that will actually be an abstract base class) which STL container I will actually use in the concrete class. I therefore don't want to have my methods return std::list::iterator or std::vector::iterator...
I tried this:
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;
};
But this is not correct because a vector::const_iterator can't be used to create an ArcIterator. So what can be this ArcIterator?
I found this paper about Custom Iterators for the STL but it did not help. I must be a bit heavy today... ;)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
因为 std::vector 保证有连续的存储,所以这样做应该是完美的:
基本上,指针的功能足够像随机访问迭代器,它们是一个足够的替代品。
Well because
std::vector
is guaranteed to have contiguous storage, it should be perfect fine to do this:Basically, pointers function enough like random access iterators that they are a sufficient replacement.
我认为应该有一种方法可以通过直接的 STL 来做到这一点,类似于您想要做的事情。
如果没有,您可能需要考虑使用 boost 的迭代器外观和适配器,您可以在其中定义自己的迭代器或将其他对象适配到迭代器中。
I want to think there should be a way to do this through straight STL, similar to what you are trying to do.
If not, you may want to look into using boost's iterator facades and adaptors where you can define your own iterators or adapt other objects into iterators.
要隐藏迭代器基于
std::vector::iterator
的事实,您需要一个委托给std::vector的迭代器类: :迭代器
。std::iterator
不会执行此操作。如果您查看编译器的 C++ 标准库中的头文件,您可能会发现
std::iterator
本身并不是很有用,除非您需要的只是一个为std::iterator 定义 typedef 的类。 code>iterator_category
、value_type
等。正如 Doug T. 在他的回答中提到的,boost 库有一些类可以更轻松地编写迭代器。 特别是
boost::indirect_iteratorArc
而不是Arc*
,code> 可能会有所帮助。To hide the fact that your iterators are based on
std::vector<Arc*>::iterator
you need an iterator class that delegates tostd::vector<Arc*>::iterator
.std::iterator
does not do this.If you look at the header files in your compiler's C++ standard library, you may find that
std::iterator
isn't very useful on its own, unless all you need is a class that defines typedefs foriterator_category
,value_type
, etc.As Doug T. mentioned in his answer, the boost library has classes that make it easier to write iterators. In particular,
boost::indirect_iterator
might be helpful if you want your iterators to return anArc
when dereferenced instead of anArc*
.考虑使用 访客模式 并反转关系:而不是向图形结构询问容器数据,您给图一个函子,并让图将该函子应用于其数据。
访问者模式是图形上常用的模式,请查看 boost 的有关访问者概念的图形库文档。
Consider using the Visitor Pattern and inverting the relationship: instead of asking the graph structure for a container of data, you give the graph a functor and let the graph apply that functor to its data.
The visitor pattern is a commonly used pattern on graphs, check out boost's graph library documentation on visitors concepts.
如果您确实不希望该类的客户端知道它在下面使用向量,但仍然希望他们能够以某种方式迭代它,那么您很可能需要创建一个将其所有方法转发到 std 的类::向量::迭代器。
另一种方法是根据 Node 应该使用的容器类型来模板化 Node。 然后客户明确知道它正在使用什么类型的容器,因为他们告诉他们使用它。
就我个人而言,我认为将向量封装远离用户通常是没有意义的,但仍然提供其大部分(甚至部分)接口。 它的封装层太薄,无法真正提供任何好处。
If you really don't want the client's of that class to know that it uses a vector underneath, but still want them to be able to somehow iterate over it, you most likely will need to create a class that forwards all its methods to std::vector::iterator.
An alternative would be to templatize Node based on the type of container it should use underneath. Then the clients specifically know what type of container it is using because they told them to use it.
Personally I don't think it usually makes sense to encapsulate the vector away from the user, but still provide most (or even some) of its interface. Its too thin of an encapsulation layer to really provide any benefit.
我查看了头文件 VECTOR.h
是一个typedef,
它是你的ArcIterator吗? 喜欢:
I looked in the header file VECTOR.
is a typedef for
Could that be your ArcIterator? Like:
您可以模板化 Node 类,并在其中 typedef iterator 和 const_iterator。
例如:
我还没有尝试过这段代码,但它给了你这个想法。 但是,您必须注意,使用 ConstArcIterator 只会禁止修改 Arc 的指针,而不允许修改 Arc 本身(例如通过非常量方法)。
You could templatize the Node class, and typedef both iterator and const_iterator in it.
For example:
I haven't tried this code, but it gives you the idea. However, you have to notice that using a ConstArcIterator will just disallow the modification of the pointer to the Arc, not the modification of the Arc itself (through non-const methods for example).
C++0x 将允许您通过自动类型确定来完成此操作。
在新标准中,这个
for (vector::const_iterator itr = myvec.begin(); itr != myvec.end(); ++itr
可以用这个代替
for (auto itr = myvec.begin(); itr != myvec.end(); ++itr)
同样,您将能够返回任何合适的迭代器,并将其存储起来在
auto
变量中。在新标准生效之前,您必须模板化您的类,或者提供一个抽象接口来访问列表/向量的元素。 例如,您可以通过在成员变量中存储迭代器并提供成员函数(例如
begin()
和next()
)来实现这一点。 当然,这意味着一次只有一个循环可以安全地迭代您的元素。C++0x will allow you do this with automatic type determination.
In the new standard, this
for (vector::const_iterator itr = myvec.begin(); itr != myvec.end(); ++itr
can be replaced with this
for (auto itr = myvec.begin(); itr != myvec.end(); ++itr)
By the same token, you will be able to return whatever iterator is appropriate, and store it in an
auto
variable.Until the new standard kicks in, you would have to either templatize your class, or provide an abstract interface to access the elements of your list/vector. For instance, you can do that by storing an iterator in member variable, and provide member functions, like
begin()
andnext()
. This, of course, would mean that only one loop at a time can safely iterate over your elements.试试这个:
并在代码的其余部分使用 Node::iterator。 当/如果您更改容器时,您必须在一个位置更改 typedef。 (您可以进一步使用额外的 typedef 进行存储,在本例中为向量。)
至于 const 问题,要么将向量的 const_iterator 定义为迭代器,要么将双迭代器类型(const 和非 const 版本)定义为矢量确实如此。
Try this:
And use Node::iterator in the rest of the code. When/if you change the container, you have to change the typedef in a single place. (You could take this one step further with additional typedef for the storage, in this case vector.)
As for the const issue, either define vector's const_iterator to be your iterator, or define double iterator types (const and non-const version) as vector does.
看看 Adobe 的
any_iterator
:这个类使用了一种称为类型擦除,通过它,底层迭代器类型被隐藏在抽象接口后面。 请注意:使用any_iterator
会因虚拟调度而导致运行时损失。Have a look at Adobe's
any_iterator
: this class uses a technique called type erase by which the underyling iterator type is hidden behind an abstract interface. Beware: the use ofany_iterator
incurs a runtime penalty due to virtual dispatching.