I l@ve RuBoard |
![]() ![]() |
3.2 Defining TypelistsFor a variety of reasons, C++ is a language that leads its users sometimes to say, "These are the smartest five lines of code I ever wrote." Maybe it is its semantic richness or the ever-exciting (and surprising?) way its features interact. In line with this tradition, typelists are fundamentally very simple: template <class T, class U> struct Typelist { typedef T Head; typedef U Tail; }; namespace TL { ...typelist algorithms ... } Everything related to typelists, except the definition of Typelist itself, lives in the TL namespace. In turn, TL is inside the Loki namespace, as is all of Loki's code. To simplify examples, this chapter omits mentioning the TL namespace. You'll have to remember it when using the Typelist.h header. (If you forget, the compiler will remind you.) Typelist holds two types. They are accessible through the Head and Tail inner names. That's it! We don't need typelists that hold three or more elements, because we already have them. For instance, here's a typelist of three elements holding the three char variants of C++: typedef Typelist<char, Typelist<signed char, unsigned char> > CharList; (Notice the annoying, but required, space between the two > tokens at the end.) Typelists are devoid of any value: Their bodies are empty, they don't hold any state, and they don't define any functionality. At runtime, typelists don't carry any value at all. Their only raison d'âtre is to carry type information. It follows that any typelist processing must necessarily occur at compile time, not at runtime. Typelists are not meant to be instantiated, although there's no harm in doing this. Thus, whenever this book talks about "a typelist," it really is referring to a typelist type, not a typelist value. Typelist values are not interesting; only their types are of use. (Section 3.13.2 shows how to use typelists to create collections of values.) The property of templates used here is that a template parameter can be any type, including another instantiation of the same template. This is an old, well-known property of templates, often used to implement ad hoc matrices as vector< vector<double> >. Because Typelist accepts two parameters, we can always extend a given Typelist by replacing one of the parameters with another Typelist, ad infinitum. There is a little problem, though. We can express typelists of two types or more, but we're unable to express typelists containing zero or one type. What's needed is a null list type, and the NullType class described in Chapter 2 is exactly suited for such uses. We establish the convention that every typelist must end with a NullType. NullType serves as a useful termination marker, much like the \0 that helps traditional C string functions. Now we can define a typelist of only one element: // See Chapter 2 for the definition of NullType typedef Typelist<int, NullType> OneTypeOnly; The typelist containing the three char variants becomes typedef Typelist<char, Typelist<signed char, Typelist<unsigned char, NullType> > > AllCharTypes; Therefore, we have obtained an open-ended Typelist template that can, by compounding a basic cell, hold any number of types. Let's see now how we can manipulate typelists. (Again, this means Typelist types, not Typelist objects.) Prepare for an interesting journey. From here on we delve into the underground of C++, a world with strange, new rules—the world of compile-time programming. |
I l@ve RuBoard |
![]() ![]() |