Re: container traits
Louis Lavery wrote:
Is there a fundamental reason why the forward definition of
a container's iterators is not possible?
No reason, since it is possible.
Something akin to
boost's adjacency_list_traits class[1] but for std lists etc.
With such a mechanism, writing self (or mutually) referencing
containers would be a lot easier (in fact, as things are, it
is not possible to have a std::list of Ts that hold iterators
to themselves).
There is no problem with declaring a std::list of class objects - each
of which contains an iterator for the same type of std::list that is
being declared.
I know this can be modeled by, say, a std::list of T*s and
(depending how close a model you want) wrapping that list's
iterator in a transform iterator that dereferences the T*s.
But all that code is, well, code - and as such is bloat.
It seems to me to be unnecessary as both of the two compilers
I use (vc7 and gcc 3.2) happily accept this code...
struct T;
typedef std::list<T>::iterator tlist_iterator; // <- UB
struct T {
tlist_iterator iter;
};
std::list<T> tlist;
which, although is formally UB, implies it's possible.
Both compilers should accept this code - there is nothing undefined
about it at all. The tlist_iterator typedef is neither an explicit
instantiation nor a specialization of std::list::iterator (in fact, the
word "template" does not even appear anywhere in the declaration).
Therefore tlist_iterator is simply an ordinary typedef. Incidentally,
there is no requirement at this point that the "T" class ever be
defined in the program. Instead, std::list<T> and its individual data
members will be instantiated on a case-by-case basis, and only as
needed to complete the program's semantics.
It may be helpful to recall that the Standard Library's iterator
classes have "pointer-like" semantics (and some may in fact be
implemented as pointers). So, just as an object can declare a pointer
to its own type as one of its members, there is likewise no reason why
an object cannot declare an iterator to a container of objects of its
own type as one of its own data members - exactly as demonstrated
above.
In fact, a few additional lines of code should be enough to demonstrate
that there is no undefined behavior with T at all:
int main()
{
std::list<T> tlist;
tlist.push_front(T());
tlist.push_back(T());
tlist.pop_front();
tlist.pop_back();
}
Greg
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]