|
Boost : |
From: Andrei Alexandrescu (andrewalex_at_[hidden])
Date: 2002-04-14 10:45:31
"David Abrahams" <david.abrahams_at_[hidden]> wrote in message
news:0d6401c1e319$b3082eb0$6801a8c0_at_boostconsulting.com...
> 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.
I understand that and entirely agree (well, if you agree on qualifying
"portability" with "to nonconformant compilers"). Indeed, I also
believe that most people don't write generic libraries. Most people
don't even get to write libraries. But again, how does MPL help?
Again, asking for salient examples of its usefulness is, I believe,
reasonable.
> 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<...>.
This is a good example of a real-world problem, thank you. I will
eliminate comments and blank lines from the metrics.
GenScatterHierarchy using mpl's abstractions has 23 lines, defines 3
new types, and uses 2 artifacts defined elsewhere.
Loki defines GenScatterHierarchy in 33 lines, but defines convenience
inner types Rebind and TList which I believed would be useful but I
never actually used them; since your implementation doesn't define
them, I think it is reasonable to remove them for purposes of
comparison.
This being said, an implementation of GenScatterHierarchy that works
only for dot-typelists and relies on nothing but C++ itself, has 20
lines, defines 1 new type, and doesn't use but the typelist itself.
Again, I believe GenScatterHierarchy is a good example of a real-world
need for type processing.
Now, my argument on the simplicity of the pattern-matching
implementation of GenScatterHierarchy is based on the following
points:
1. Show the sheer code to a C++ programmer. I appended the two
implementations at the end of this post.
2. 20 < 23
3. 1 < 3
4. 1 < 2
I'd like to stress an important point here. This is not a comparison
of MPL and Loki. This is a comparison of MPL with straight C++. We are
comparing code that uses MPL with code that uses pretty much nothing
but the following magic structure:
template <typename H, typename T>
struct typelist
{
typedef H head;
typedef T tail;
};
So if MPL provides that structure, in many cases one is better off by
simply using only it and nothing else.
How about DerivedToFront, could someone post an MPL implementation of
it? Here I am pretty sure that MPL will at least have a compilation
speed advantage , because Loki's algorithm is terribly inefficient. I
should have used mergesort but... deadline pressure. Nobody complained
so far :o).
Andrei
-- Appendix: --------------- Version of GenScatterHierarchy using MPL's facilities --------------- // 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> > { }; --------------- Version of GenScatterHierarchy that works on dot-typelists only --------------- ////////////////////////////////////////////////////////////////////// ////////// // class template GenScatterHierarchy // Generates a scattered hierarchy starting from a typelist and a template // Invocation (TList is a typelist, Model is a template of one arg): // GenScatterHierarchy<TList, Model> // The generated class inherits all classes generated by instantiating the // template 'Model' with the types contained in TList ////////////////////////////////////////////////////////////////////// ////////// template <class TList, template <class> class Unit> class GenScatterHierarchy; template <class T1, class T2, template <class> class Unit> class GenScatterHierarchy<Typelist<T1, T2>, Unit> : public GenScatterHierarchy<T1, Unit> , public GenScatterHierarchy<T2, Unit> { public: typedef GenScatterHierarchy<T1, Unit> LeftBase; typedef GenScatterHierarchy<T2, Unit> RightBase; }; template <class AtomicType, template <class> class Unit> class GenScatterHierarchy : public Unit<AtomicType> { typedef Unit<AtomicType> LeftBase; }; template <template <class> class Unit> class GenScatterHierarchy<NullType, Unit> { };
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk