|
Ublas : |
From: Michael Stevens (mail_at_[hidden])
Date: 2005-07-08 12:20:38
On Wednesday 06 July 2005 17:30, Ian McCulloch wrote:
> Michael Stevens wrote:
> > Dear All,
> >
> > I've been stuck on this problem for a long time and wonder if anyone
> > knows a trick which will help out.
> >
> > The problem arises in that the type of the template parameter is
> > 'incomplete' in the base class. So in the following base class:
> >
> > template <class E>
> > struct expression {
> > typedef E expression_type;
> > // typedef typename E::size_type size_type;
> > };
> >
> > we are restricted in what we can do with E. In particular it is not
> > possible to extract types out of E. The commented out typedef will fail
> > as E is incomplete. Curiously it is possible to write member functions
> > that manipulate such types.
>
> Actually, this is quite natural. For concreteness, suppose we have
>
> struct foo : expression<foo> { typedef bar size_type; };
>
> Before any members of foo are parsed, the base class expression<foo> is
> instantiated. At this point, foo is an incomplete type, so it is not
> possible for member declarations of expression<foo> to depend on types
> defined in foo itself. The dependency order is the other way around.
Agreed. In fact if you play with this you can start getting the compiler to
unbounded recursions instantiating templates. Results in spectacularly long
error messages!
>
> > What would be nice is to be able a similar function which can return 'a'.
> > But this seems impossible.
> >
> > Anyone know of a trick?
>
> The 'trick' is to move the types into a third class:
>
> // types needed by expression<E> are defined in expression_traits<E>
> template <class T> struct expression_traits {};
>
> template <class E>
> struct expression
> {
> typedef typename expression_traits<E>::size_type size_type;
>
> size_type function1() { ... }
> };
>
>
>
> struct foo;
>
> // expression_traits<E> cannot depend on member declarations in E -
> // E will be incomplete here
> template <> struct expression_traits<foo>
> {
> typedef bar size_type;
> };
>
> struct foo : expression<foo>
> {
> // all these have the same effect
> typedef typename expression_traits<foo>::size_type size_type;
> typedef typename expression<foo>::size_type size_type;
> using expression<foo>::size_type;
> };
Interesting solution using a 3rd party for traits. If I understand it
correctly it only works for a known and limited set of expressions for which
you can predefine the traits.
Thanks,
Michael