 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Charles Bissonnette Guest
|
Posted: Sun Apr 24, 2005 3:43 pm Post subject: Iterators and policy definition for iteration type |
|
|
I've wrote an iterator for my class "Seg" and and the class has an member
typedef that defines that iterator
typedef SegIter iterator;
Everything used the standard way of definining iterator from STL
SegIter is defined like this :
class SegIter : public std::iterator<std::bidirectional_iterator_tag, Seg*>
{
.....
}
Seg objects are segment from an interval tree.
When defining a region to iterate from, let's say seg1->begin() to
Seg2->end(), you can so such with an unrolled loop
Seg::iterator iter;
for(iter = seg1->begin(), iter != seg2->End(), iter++)
{
.....
}
Currently, operator++() from the iterator is hardcored to do a depth-first
from the start to the end of the segment. However, I would like to customize
the traversal algorithm through a policy class
teamplate <class TraversePolicy>
class SegIter : public TraversePolicy
{
...
}
SegIter would then require the policy class to implement the method "bool
advance(SegIter*). The This pointer is passed as pointer to the policy class
... At this point I'm not sure if this is the right usage of policies (I just
read the book Modern C++ seems like Policies is appropriate for that).
Doing so implies that the policy is not reponsible for implementing the
traversal, but instead the iterator itself. How can I tell the iterator
which algorithm to use then? I though about how STL use compile time
polymorphism and function overloading to determine the right algorithm to
use depending on the type of iterator. I thought doing the same, by defining
a bunch of classes,
struct linear_traverse_type_tag
{};
struct hierarchical_traverse_tag
{};
struct depth_first_traverse_tag :
public hierarchical_traverse_tag
{};
struct breadth_first_traverse_tag :
public hierarchical_traverse_tag
{};
struct parent_chain_traverse_tag :
public hierarchical_traverse_tag
{};
And having the iterator implementing different overloaded version of Advance
SegIter& advance(depth_first_traverse_tag &);
SegIter& advance(breadth_first_traverse_tag &);
SegIter& advance(parent_chain_traverse_tag &);
For each Policy class that I would define, they would define a typedef
_traversal with the right type mentioned above. Even better, I could have
the policy class being a template class and the argument being the traversal
tag.
template<class traversal>
class SegIter : public GenericTraversePolicy<SegIter, traversal>
{
}
In this cass, GenericTraversePolicy class is not really a policy class but
simply a templatized class that knows with overloaded Advance from the
iterator to call.
I'm really not sure if what i'm describing above is the right way of solving
this problem. My first concern is STL which expect an iterator of a class to
be of one type. That iterator cannot be templatized. Otherwize, how STL
determine with iterator to use?
I'm not so sure also if the use of STL here is the right approach too. I've
been reading the Range Concept from the Book "Imperfect C++" and it seems
like Range may also offer a better way of solving this problem.
Any feedback how to solve this problem is appreciated,
Regards,
-Charles
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Alberto Barbati Guest
|
Posted: Sun Apr 24, 2005 8:55 pm Post subject: Re: Iterators and policy definition for iteration type |
|
|
Charles Bissonnette wrote:
| Quote: | I've wrote an iterator for my class "Seg" and and the class has an member
typedef that defines that iterator
typedef SegIter iterator;
Everything used the standard way of definining iterator from STL
SegIter is defined like this :
class SegIter : public std::iterator<std::bidirectional_iterator_tag, Seg*
{
....
}
Seg objects are segment from an interval tree.
|
.....hmmm, is Seg the value type or the container type? It looks like, and
so I assume it is, the value (actually it is Seg*). The interval tree is
therefore the container, right?
| Quote: |
When defining a region to iterate from, let's say seg1->begin() to
Seg2->end(), you can so such with an unrolled loop
|
Ops! If Seg is the value type, how come it has begin() and end()
members???? They should belong to the container instead.
Moreover, a valid range is defined by two iterators "pointing to" places
in the same container, so the range should be either "seg1->begin(),
seg1->end()" or "seg2->begin(), seg2-end()". You can't take the begin
from one container and the end of another container and pretend they
describe a range. If you need to do that, then either you are very
confused or the iterator concept is not suitable for you.
| Quote: |
Seg::iterator iter;
|
This makes Seg looks like it is indeed the container type... I'm lost!
| Quote: | for(iter = seg1->begin(), iter != seg2->End(), iter++)
{
....
}
|
For custom iterators it is usally preferrable to use ++iter instead of
iter++. Dumb compilers may produce suboptimal code in presence of iter++
because they may not be able to optimize away the presence of an
unneeded temporary.
| Quote: |
Currently, operator++() from the iterator is hardcored to do a depth-first
from the start to the end of the segment. However, I would like to customize
the traversal algorithm through a policy class
teamplate <class TraversePolicy
class SegIter : public TraversePolicy
{
...
}
|
Ouch. Things are getting more complex then. If you want to stick with
the iterator approach, you end up having different iterator classes.
This approach as certain advantages, for example you won't inadventently
mix iterators with different traversal algorithms. I hope you realize,
however, that you will need to templatize function begin() and end() also:
class ???? // is it Seg or whatever?
{
template
SegIter<TraversePolicy> begin();
template <class TraversePolicy>
SegIter<TraversePolicy> end();
};
and the syntax will now change in the above example:
//Seg::iterator iter; you can no longer use this
SegIter<traversal> iter;
for(iter = seg1->begin<traversal>(),
iter != seg1->end<traversal>(), ++iter)
{
....
}
| Quote: |
SegIter would then require the policy class to implement the method "bool
advance(SegIter*). The This pointer is passed as pointer to the policy class
.. At this point I'm not sure if this is the right usage of policies (I just
read the book Modern C++ seems like Policies is appropriate for that).
Doing so implies that the policy is not reponsible for implementing the
traversal, but instead the iterator itself.
|
I don't follow you... If advance() takes a SegIter* then the traversal
is implemented by the policy. Yet you say it isn't. Please notice that
there is nothing (in the language, nor in the STL) that prevents you to
implement the traversal either in the policy or in the iterator or in
the container class or in any another place. You just have to decide
which place is better for you.
| Quote: | traversal, but instead the iterator itself. How can I tell the iterator
which algorithm to use then? I though about how STL use compile time
polymorphism and function overloading to determine the right algorithm to
use depending on the type of iterator. I thought doing the same, by defining
a bunch of classes,
struct linear_traverse_type_tag
{};
struct hierarchical_traverse_tag
{};
struct depth_first_traverse_tag :
public hierarchical_traverse_tag
{};
struct breadth_first_traverse_tag :
public hierarchical_traverse_tag
{};
struct parent_chain_traverse_tag :
public hierarchical_traverse_tag
{};
And having the iterator implementing different overloaded version of Advance
SegIter& advance(depth_first_traverse_tag &);
SegIter& advance(breadth_first_traverse_tag &);
SegIter& advance(parent_chain_traverse_tag &);
|
You are making it more complicated than it should. Why don't you just
define the traversal in the policy class itself? Like this:
struct linear_traverse
{
static void advance(SegIter<linear_traverse>& iter);
};
struct depth_first_traverse
{
static void advance(SegIter<depth_first_traverse>& iter);
};
// ...
then the iterator is implemented like this:
template <class TraversePolicy>
class SegIter<TraversePolicy>
{
//...
SegIter& operator++()
{
TraversePolicy::advance(*this);
return *this;
}
};
(this is in fact a template-based application of the GoF Strategy pattern)
| Quote: | For each Policy class that I would define, they would define a typedef
_traversal with the right type mentioned above. Even better, I could have
the policy class being a template class and the argument being the traversal
tag.
template
class SegIter : public GenericTraversePolicy
{
}
|
Another unnecessary complication, IMHO.
| Quote: |
I'm really not sure if what i'm describing above is the right way of solving
this problem. My first concern is STL which expect an iterator of a class to
be of one type. That iterator cannot be templatized. Otherwize, how STL
determine with iterator to use?
|
Why do you say that iterators cannot be templatized? The only problem
with templatized iterators is that you lose the possibility to write:
typedef SegIter iterator;
but nobody will yell at you if you don't provide that. It's just
syntactic sugar and that's not what makes a class an iterator class ;-)
| Quote: | I'm not so sure also if the use of STL here is the right approach too. I've
been reading the Range Concept from the Book "Imperfect C++" and it seems
like Range may also offer a better way of solving this problem.
|
I didn't read the book so I can't help you here. Of course there may be
other concepts that may suit you better than the iterator concept.
Programming means making choices, you know. Most of the times they are
not black vs. white choices, there are a lot of shades of grey ;-)
Alberto
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|