Boost logo

Boost :

From: Brian McNamara (lorgon_at_[hidden])
Date: 2003-10-04 18:36:26


On Sat, Oct 04, 2003 at 05:48:19PM -0400, David Abrahams wrote:
> Brian McNamara <lorgon_at_[hidden]> writes:
> > The nested templates are named as the individual traits of interest, and
> > they each have a default (dummy) parameter. As a result, each
> > individual trait is only computed on demand (and is also individually
> > MPL-able). But all the related traits are grouped into a common
> > "supertraits" class, which groups related traits conceptually and also
> > helps prevent namespace pollution. I think this may be a
> > nearly-perfect overall solution which gives the best of both worlds.
> >
> > That looks really clever to me, and I'd appreciate comments on the idea
> > (especially from David).
>
> Sorry, looks uglier than my first alternative, and much more verbose,
> and much *less* MPL-able.

Ok, let me start over from scratch because in my last message I chose a
poor example and I screwed up some of the MPL details.

First, here's my statement of the original problem. (It might not
actually match the real problem being discussed--I haven't followed the
whole thread--but I think it'll be close enough to be useful.) Someone
defines an interface like this

   // C is some container type
   container_traits<C>::value_type
   container_traits<C>::iterator_type
   ... // and a bunch of other foo_types

This is nice, but there are two problems with this approach. First, when
I ask for

   container_traits<C>::value_type

the compiler will instantiate the entire container_traits class, which
means that the types for iterator_type, foo_type, etc. will all get
computed, even though I am not asking for them. Second, there are no
MPL metafunctions here, which makes the interfaces not very amenable to
MPL.

One solution, which I think is the solution you are suggesting, is to
make individual traits:

   container_value_type<C>::type
   container_iterator_type<C>::type
   ... // etc for each "foo"

This solves both of the problems above: each type is computed
"independently", and each trait is an MPL metafunction. However the
weakness here is that now we have polluted the namespace with many
new names (rather than just one ("container_traits")), and the
conceptual-relatedness of the group of traits is no longer expressed
by a structural grouping in the code.

In order to have our cake and eat it too, I propose this:

   container_traits<C>::value_type<>::type
   container_traits<C>::iterator_type<>::type
   ... // etc for each foo

Now we reap the advantages of both solutions. That is

 - we have conceptually grouped related traits into a single traits
   class (container_traits<C>)

 - each individual trait is an MPL metafunction (e.g.
   container_traits<C>::value_type<>)

 - asking for one trait (e.g. value_type) does not cause other trait
   values (e.g. iterator_type) to get computed

 - we have only introduced one name (container_traits) into the (boost)
   global namespace

Agree/disagree?

Mostly unrelated to the above:

> How do you express
>
> argument_type<F,_1>::type
>
> with that system??

No clues here; sadly I still only a tiny bit about MPL, just enough
(hopefully!) to participate in this discussion.

-- 
-Brian McNamara (lorgon_at_[hidden])

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