Boost logo

Boost :

From: Jeremy Siek (jsiek_at_[hidden])
Date: 2002-02-06 22:49:35


On Wed, 6 Feb 2002, Beman Dawes wrote:
bdawes>
bdawes> What is wrong with forwarding classes (until typedef
bdawes> templates make it into the language)?
bdawes>
bdawes> template <typename T>
bdawes> struct specific_a : public generic<T, policy_a>
bdawes> { ... forwarding ctors, etc. };
bdawes>
bdawes> template <typename T>
bdawes> struct specific_b : public generic<T, policy_b>
bdawes> { ... forwarding ctors, etc. };
bdawes>
bdawes> Or am I missing something?

I'm afraid there are lots of differences between forwarding classes and
template typedefs/type generators. Back when template typedefs were first
proposed, I don't think people were aware of the differences. I wasn't
there, but from talks with Bjarne I gather that the original proposal
didn't go through because there wasn't a list of examples to show why
forwarding classes don't work, but now there are plenty of examples.

Perhaps the most convincing example comes from the iterator_adaptor class.
The purpose of the iterator_adaptor class is to facilitate creating more
specialized iterators like the transform_iterator. So, let us look at what
happens if we try to implement tranform_iterator as a forwarding class,
via inheriting from iterator_adaptor. Lets focus on operator++.

template <...>
class iterator_adaptor {
  iterator_adaptor operator++(int) {
    iterator_adaptor tmp(*this); ++*this; return tmp;
  }
};

template <...>
class transform_iterator : public iterator_adaptor {
  value_type operator*() const {
    return fun(iterator_adaptor::operator*());
  }
  UnaryFunction fun;
};

So hopefully transform_iterator inherits operator++ and things work fine?
No cigar. The return type of operator++ for an iterator must be the same
iterator type. So for transform_iterator the return type of operator++
better be transform_iterator. However, in the above implementation the
return type is iterator_adaptor, not transform_iterator. So have a
transform_iterator t_it and do this: *(t_it++) you'll get operator* of
the base iterator_adaptor, missing the operator* provided in
transform_iterator.

Now, you can solve the above problem using the Barton and Nackman trick,
passing the derived type up into the base class iterator_adaptor. We do
this in booost/operators.hpp and also in adjacency_list in the BGL.
However, this has its own complications, and in general I've found it
easier to go the type generator route than the B&N route.

Cheers,
Jeremy

----------------------------------------------------------------------
 Jeremy Siek http://php.indiana.edu/~jsiek/
 Ph.D. Student, Indiana Univ. B'ton email: jsiek_at_[hidden]
 C++ Booster (http://www.boost.org) office phone: (812) 855-3608
----------------------------------------------------------------------


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk