Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What should the iterator type be in this C++ template?

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?

like image 323
Bob Murphy Avatar asked Feb 08 '10 01:02

Bob Murphy


People also ask

How do I find my iterator type?

Iterator type can be checked by using typeid.

What is the datatype of iterator?

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.

What is an iterator What are types of iterators?

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.

Does C have iterator?

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.


2 Answers

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;
    // ...
};
like image 59
Georg Fritzsche Avatar answered Oct 05 '22 22:10

Georg Fritzsche


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.

like image 34
e.James Avatar answered Oct 06 '22 00:10

e.James