I l@ve RuBoard |
![]() ![]() |
3.12 Partially Ordering TypelistsSuppose we want to order a typelist by inheritance relationship. We'd like, for instance, derived types to appear before base types. For example, say we have a class hierarchy like the one in Figure 3.1: Figure 3.1. A simple class hierarchyIf we have this typelist: TYPELIST_4(Widget, ScrollBar, Button, GraphicButton) the challenge is to transform it into TYPELIST_4(ScrollBar, GraphicButton, Button, Widget) That is, we need to bring the most derived types to the front and leave the order of sibling types unaltered. This seems like an exercise of intellectual value only, but there are important practical applications for it. Scanning a typelist ordered with the most derived types first ensures a bottom-up traversal of a class hierarchy. The double-dispatch engine in Chapter 11 applies this important property for figuring out information about types. When ordering a collection, we need an ordering function. We already have a compile-time means to detect inheritance relationships, described in detail in Chapter 2. Recall that we have a handy macro, SUPERSUBCLASS(T, U), which evaluates to true if U is derived from T. We just have to combine the inheritance detection mechanism with typelists. We cannot use a full-fledged sorting algorithm here because we don't have a total ordering relationship; we don't have the equivalent of operator< for classes. Two sibling classes cannot be ordered by SUPERSUBCLASS(T, U). We will therefore use a custom algorithm that will bring derived classes to the front and will let other classes remain in the same relative positions.
When this algorithm is applied to a typelist, derived types will migrate to the top of the typelist, and base types will be pushed to the bottom. There is a piece missing here—the algorithm that finds the most derived type of a given type in a typelist. Because SUPERSUBCLASS yields a compile-time Boolean value, we'll find the little Select class template (also presented in Chapter 2) to be useful. Recall that Select is a template that selects one of two types based on a compile-time Boolean constant. The MostDerived algorithm accepts a typelist and a type Base and returns the most derived type from Base in the typelist (or possibly Base itself, if no derived type is found). It looks like this:
The implementation of MostDerived is as follows: template <class TList, class T> struct MostDerived; template <class T> struct MostDerived<NullType, T> { typedef T Result; }; template <class Head, class Tail, class T> struct MostDerived<Typelist<Head, Tail>, T> { private: typedef typename MostDerived<Tail, T>::Result Candidate; public: typedef typename Select< SUPERSUBCLASS(Candidate, Head), Head, Candidate>::Result Result; }; The DerivedToFront algorithm uses MostDerived as a primitive. Here is DerivedToFront's implementation: template <class T> struct DerivedToFront; template <> struct DerivedToFront<NullType> { typedef NullType Result; }; template <class Head, class Tail> struct DerivedToFront< Typelist<Head, Tail> > { private: typedef typename MostDerived<Tail, Head>::Result TheMostDerived; typedef typename Replace<Tail, TheMostDerived, Head>::Result L; public: typedef Typelist<TheMostDerived, L> Result; }; This complex typelist manipulation is of considerable strength. The DerivedToFront transformation effectively automates type processing that otherwise can be performed only with much discipline and attention. Automatic maintenance of parallel class hierarchies, anyone? |
I l@ve RuBoard |
![]() ![]() |