tags:

views:

103

answers:

3

I'm trying to create a list of objects, where each object also stores 'ownership' - ie, it knows which list holds it.

In a non-template situation, it's straightforward:

class FooList;  // forward declaration

class FooItem
{
  public:
     FooList *owner;
  ...
};

class FooList: private std::list<FooItem>
{
  ...
};

However, the list class is a template, based on the contained object type, and I'm struggling to work out how to specify this. I reckon the FooItem class now needs to be a template because the type of 'owner' can vary:

template <class E> class FooItem
{
  public:
     std::list<E> *owner;
};

template <class E> class FooList: private std::list<E>
{
  ...
};

But, now given my two templates, how can I define the new types I want? The snippet below is what I think I need, but it gives "error: Multiple declaration for BarItem".

class BarItem;

typedef FooList<BarItem> BarList;
typedef FooItem<BarList> BarItem;

EDIT:

Thanks to those who pointed out the issue of std::list<E> instead of std::list<FooItem<E> >


EDIT 2: Renamed classes to Base, Derived, BaseList, DerivedList.

My real problem was the 'circular typedef'. After some more tinkering, I think this will do what I require. It creates a 'real' BarItem class rather than just a typedef, but seems to at least compile now.

template <class E> class BaseList; // forward declaration

template <class E> class Base
{
  public:
     BaseList< Base<E> > *owner;
};

template <class E> class BaseList: private std::list< E >
{
};

// typedef Base<BaseList<Derived> > Derived;  //This won't compile, unsurprisingly.

class Derived : public Base < BaseList<Derived> >  // Surprisingly, this seems to.
{
...
};

typedef BaseList<Derived> DerivedList;

Does this seem to make sense? Is it a common idiom or something horrible?

+3  A: 

Is that last set of typedef statements correct? You posted this:

class BarItem;

typedef FooList<BarItem> BarList;
typedef FooItem<BarList> BarItem;

It's somewhat recursive, right? The first statement says there's a class BarItem that exists elsewhere. The second statement says that the type FooList<BarItem> (a list of BarItem objects) can also be referred to as BarList. The third statement says that the type FooItem<BarList> can also be referred to as BarItem, but BarItem was already defined as a type by the class BarItem statement.

So you're saying that BarItem is a type all to itself (via the class statement), but you're also saying that BarItem is an alias for the type FooItem<BarList>. Hence the conflict.

Brent Nash
`So you're saying that BarItem is a type all to itself?` :No - I'm trying to somehow 'forward declare' BarItem, but I'm struggling with the syntax.
Roddy
The point I was attempting to make was that by forward declaring `BarItem` (which you can do by something like `template <class E> class BarItem;` if the class is templated) and then also trying to use it on the right hand side of a `typedef` expression, you're going to get a conflict. If there's a class that exists somewhere called `BarItem`, then you can't also do `typedef SOME_TYPENAME_HERE BarItem`.
Brent Nash
@Brent, I guess I was trying to forward-typedef a typedef... doh. Does my updated question (with possible solution) make more sense now?
Roddy
+4  A: 

Are you sure you didn't want:

template <class E> class FooItem
{
  public:
     std::list< FooItem<E> > *owner; // owned by a list of FooItem<E>, not raw E
};

template <class E> class FooList: private std::list< FooItem<E> > // is a list of FooItem<E>, not raw E
{
  ...
};

The error you are getting is because you forward declare the class BarItem but later try to redefine that name using typedef. Not sure what you're trying to accomplish, but you'll need to introduce a third name. Maybe you meant:

class Bar;
typedef FooItem<Bar> BarItem;
typedef FooList<Bar> BarList;

EDIT: The new code you've posted certainly compiles, but seems very awkward (for one thing, the naming seems really confusing). Perhaps you should ask a new question with a more concrete example of why you think you need an 'item which is an item of lists of itself' and see if others can come up with a less awkward design.

Nick Meyer
Thanks for the correction. I've updated the question showing what I think is an 'answer' to my problem.
Roddy
+3  A: 

If you just want to generalize your first approach to a templated FooItem class, it would look like this:

template <class E> class FooList; // forward declaration

template <class E> class FooItem
{
  public:
     FooList<E> *owner;
  ...
};

template <class E> class FooList: private std::list< FooItem<E> >
{
  ...
};

If that is not what you want I'm not sure what exactly you are attempting to do.

sth