While working on some graphics code a while back, I wrote Rect and Region classes using ints as the underlying coordinate holder, and that worked fine. The Region was implemented as a simple class extension to an STL list, and just contains a list of Rects.
Now I also need the same kinds of classes using doubles as the underlying coordinate holder, and decided to try my hand at templatizing it. So I basically replaced "int" with "typename T" in an intelligent manner and fixed the problems.
But there's one remaining problem that has me stumped. I want to calculate a Region's bounding box by doing a union on all the Rects that comprise it. That works fine when not templatized, but g++ chokes on the list iterator when this is templatized.
Here's the relevant code:
// Rect class that always remains normalized
template <typename T>
class KRect
{
public:
// Ctors
KRect(void)
: _l(0), _t(0), _r(0), _b(0)
{
}
void unionRect(const KRect& r)
{
...
}
private:
T _l, _t, _r, _b;
};
// Region class - this is very brain-dead
template <typename T>
class KRegion : public std::list< KRect<T> >
{
public:
...
// Accessors
KRect<T> boundingBox(void)
{
KRect<T> r;
iterator i;
for (i = this->begin(); i != this->end(); i++)
{
r.unionRect(*i);
}
return r;
}
...
};
When that code isn't part of a template, so that T is definite (e.g. an int), the "iterator i" line works fine. But in what you see above, g++ on Ubuntu emits errors which I don't find very informative:
include/KGraphicsUtils.h: In member function ‘KRect<T> KRegion<T>::boundingBox()’:
include/KGraphicsUtils.h:196: error: expected ‘;’ before ‘i’
include/KGraphicsUtils.h:197: error: ‘i’ was not declared in this scope
include/KGraphicsUtils.h: In member function ‘KRect<T> KRegion<T>::boundingBox() [with T = int]’:
--- redacted ---:111: instantiated from here
include/KGraphicsUtils.h:196: error: dependent-name ‘std::foo::iterator’ is parsed as a non-type, but instantiation yields a type
include/KGraphicsUtils.h:196: note: say ‘typename std::foo::iterator’ if a type is meant
My guess is this is a type qualification issue with some template-y spin I'm not familiar with. I've tried all kinds of things like:
std::list< KRect<T> >::iterator i;
this->iterator i;
but nothing seems to work.
Any suggestions?
Iterator type can be checked by using typeid.
The type of it is map<string,int>::iterator , which is a class with a bunch of operators overloaded. For some container types, Container::iterator may be a raw pointer type.
Iterators are used to traverse from one element to another element, a process is known as iterating through the container. The main advantage of an iterator is to provide a common interface for all the containers type. Iterators make the algorithm independent of the type of the container used.
An iterator is an object that allows you to step through the contents of another object, by providing convenient operations for getting the first element, testing when you are done, and getting the next element if you are not. In C, we try to design iterators to have operations that fit well in the top of a for loop.
iterator
is a dependent type (it depends on a template argument) and needs to be prefixed with typename
:
typename std::list< KRect<T> >::iterator i;
Better style would be to provide a class-wide typedef:
template <typename T>
class KRegion : public std::list< KRect<T> >
{
typedef std::list< KRect<T> > base;
typedef typename base::iterator iterator;
// ...
};
I think gf has your answer, but I'd like to suggest having the region manage a list as a member instead of a base class:
template <typename T>
class KRegion
{
protected:
typedef std::list< KRect<T> > ListType;
ListType list;
public:
...
// Accessors
void addRect(KRect<T> & rect) { list->push_back(rect); }
...
KRect<T> boundingBox(void)
{
KRect<T> r;
ListType::iterator i;
for (i = list->begin(); i != list->end(); i++)
{
r.unionRect(*i);
}
return r;
}
...
};
My motivation for this suggestion is that you may, one day, want to use a different container for storing your KRects, and having the list as an internal member would let you do so without breaking all of your client code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With