Boost logo

Ublas :

From: Ian McCulloch (ianmcc_at_[hidden])
Date: 2005-07-06 10:30:10

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.

> So the following is fine.
> template <class E>
> struct expression {
> typedef E expression_type;
> static void function1 ()
> {
> typename E::size_type a;
> }
> };

Instantiating a class only instantiates *declarations*, it does not
instantiate member functions. Member functions are only instantiated at
the point of actually using them (so if they are not mentioned anywhere,
they are never instantiated). By the time function1() is instantiated, foo
and expression<foo> will have been previously instantiated.

> 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;