Boost logo

Boost :

From: David Abrahams (david.abrahams_at_[hidden])
Date: 2002-04-13 13:33:20


----- Original Message -----
From: "Andrei Alexandrescu" <andrewalex_at_[hidden]>

> The implementation of count_if as a library artifact is largely
> irrelevant. As long as a library function respects an interface, the
> library user can only appreciate a more sophisticated implementation.
> I understand we are discussing count_if as an example of typical
> implementation of a user-defined algorithm.
>
> Again, let me post some simple measurements of the two variants of
> count_if.
>
> The count_if implementation using mpl has 34 lines, defines 3 new
> types, 1 new namespace, and relies on 5 artifacts defined elsewhere.
>
> The count-if that works only for dot-typelists has 15 lines, defines 1
> new type, and does not rely on any other artifacts than the typelist
> itself.
>
> This being said, my argument on the simplicity of the pattern-matching
> implementation of count_if is based on the following points:
>
> 1. Show the sheer code to a C++ programmer. For completeness' sake, I
> appended the code at the end of this post.
>
> 2. 15 < 34
>
> 3. 1 < 3
>
> 4. 0 < 1
>
> 5. 1 < 5

Yes, and you can write the simple dot-typelist example using an MPL
typelist, nearly as easily... if you're willing to give up portability,
efficiency on large sequences, and flexibility. Aleksey's example shows
how to write a "generic" count-if. The dot-typelist example is
essentially non-polymorphic (in the compile-time world). There's
definitely a place for that sort of code - most people, I daresay, are
not writing generic libraries. However, I don't think it's a long-term
win for MPL documentation to stress techniques for writing
typelist-specific algorithms when it provides such useful tools for
generic algorithms.

> Several people have repeatedly asked for self-contained, sensical
> examples demonstrating that using the style pioneered by MPL leads to
> a good solution. I believe this is reasonable to ask for.

I agree; unfortunately all of the really heavy-duty examples I've
generated which absolutely /need/ the abstractions of MPL in order to be
manageable are someone else's proprietary code. However, I think the MPL
rewrite of your GenScatterHierarchy is a good simple example. I
purposely left in all the comments and namespace qualifications just to
make this as verbose as possible. I did allow myself the small luxury of
using boost::mpl::apply<F,...> instead of F::template apply<...>.

// warning, untested

   // The product of GenScatterHierarchy will always be one of these,
   // with leaves being the classes in the type list.
   template <class L, class R>
   struct InheritTwo : public L , public R
   {
     typedef L Left;
     typedef R Right;
   };

// F is the transformation that will be bound into
// this function object and applied to each element;
// think of this as a parameterized function adaptor.
template <class F>
struct inherit_transformed
{
    // This is the function object's operator()()
    template <class Product, class Element>
    struct apply
    {
        // first transform the type
        typedef typename boost::mpl::apply<F,Element>::type transformed;

        // This is the return value: we inherit from the
        // current element and everything accumulated so far
        typedef InheritTwo<transformed_type, Product> type;
    };
};

// Now we can define GenScatterHierarchy

   template <class Sequence, class Transformation>
   struct GenScatterHierarchy
        : boost::mpl::fold<
            Sequence, EmptyType, inherit_transformed<Transformation>
>
   {
   };

Note that find_if is a bit artificially biased away from MPL idioms,
since it manipulates integral constants, and MPL adds a uniformity layer
to make them look like types.

-Dave


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