|
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