|
Boost : |
From: Peter Dimov (pdimov_at_[hidden])
Date: 2001-12-15 11:53:03
The recent "meta-activity" on the list prompted me to try and actually
metaprogram something. I recalled that Dave Abrahams mentioned sorting a
list at compile time; this looked like a good "assignment."
The result is at the end of this message; I'd be interested to compare it
with Dave's original compile-time sort, or another MPL-based or influenced
sort.
What I learned from writing the sort<> metafunction (I deliberately did not
look at MPL first) and then comparing with MPL:
* the MPL concept of "metafunction" (class with a nested template apply<>)
is pretty much necessary given the current state of C++.
* the MPL 'port' of <functional> is very useful and independent of the
iterative-vs-recursive debate. Perhaps because <functional> itself is a
port. ;-)
* many of the MPL algorithms are very useful and necessary; there is a bit
of a naming conflict between the STL and the established 'functional' names
but it's not a showstopper.
* MPL is dominated by an iterative idiom, AFAICS. Nearly everything is done
with a for-style loop. This might have its benefits (more gentle learning
curve for C++/STL programmers) but I think that the recursive style of
programming sometimes produces more elegant and readable functions.
* MPL tries to emulate the STL to the extent of using iterators into
abstract sequences, and providing different 'containers' with their
associated 'traits.' It even has a 'clear' function that returns a new empty
'container' of the same type.
In contrast, Lisp builds everything out of pairs; its only data structure is
the binary tree. A Lisp tree is nearly always a slist; nevertheless,
sometimes a binary tree is a better fit for the concept being modeled.
Both approaches have pros and cons. I prefer the traditional Lisp way.
Without a motivating example to the contrary, I'm inclined to think that in
this area MPL is over-generic.
-- Peter Dimov Multi Media Ltd. #include <iostream> #include <typeinfo> template<class, class> struct pair; class nil; template<int I> struct value_wrapper { enum { value = I }; }; template<class, class> struct less_helper; template<int A, int B> struct less_helper<value_wrapper<A>, value_wrapper<B> > { enum { value = (A < B) }; typedef value_wrapper<value> type; }; struct less { template<class A, class B> struct apply { typedef typename less_helper<A, B>::type type; }; }; template<class MF> struct not2 { template<class A, class B> struct apply { typedef typename MF::template apply<A, B>::type temp; enum { value = !temp::value }; typedef value_wrapper<value> type; }; }; template<class, class> struct append; template<class A, class B, class C> struct append<pair<A, B>, C> { typedef pair<A, typename append<B, C>::type> type; }; template<class B> struct append<nil, B> { typedef B type; }; template<class P, class V> struct bind1st { template<class A> struct apply { typedef typename P::template apply<V, A>::type type; }; }; template<class P, class V> struct bind2nd { template<class A> struct apply { typedef typename P::template apply<A, V>::type type; }; }; template<int A, class B, class C> struct ct_if { typedef B type; }; template<class B, class C> struct ct_if<0, B, C> { typedef C type; }; template<class L, class P> struct select_if; template<class P> struct select_if<nil, P> { typedef nil type; }; template<class A, class B, class P> struct select_if<pair<A, B>, P> { typedef typename select_if<B, P>::type rest; typedef typename P::template apply<A>::type cond; enum { cv = cond::value }; typedef typename ct_if<cv, pair<A, rest>, rest>::type type; }; template<class L> struct sort; template<> struct sort<nil> { typedef nil type; }; template<class A, class B> struct sort<pair<A, B> > { typedef typename select_if<B, bind2nd<less, A> >::type before; typedef typename select_if<B, bind2nd<not2<less>, A> >::type after; typedef typename append<typename sort<before>::type, pair<A, typename sort<after>::type> >::type type; }; int main() { typedef pair<value_wrapper<11>, pair<value_wrapper<5>, pair<value_wrapper<-1>, pair<value_wrapper<3>, nil> > > > list; typedef sort<list>::type list4; std::cout << typeid(list4).name() << '\n'; }
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk