I l@ve RuBoard |
3.1 The Need for TypelistsSometimes you must repeat the same code for a number of types, and templates cannot be of help. Consider, for instance, implementing an Abstract Factory (Gamma et al. 1995). Here you define one virtual function for each type in a collection of types known at design time: class WidgetFactory { public: virtual Window* CreateWindow() = 0; virtual Button* CreateButton() = 0; virtual ScrollBar* CreateScrollBar() = 0; }; If you want to generalize the concept of Abstract Factory and put it into a library, you have to make it possible for the user to create factories of arbitrary collections of types—not just Window, Button, and ScrollBar. Templates don't support this feature out of the box. Although at first Abstract Factory may not seem to provide much opportunity for abstraction and generalization, there are a few things that make the investigation worthwhile:
Let's put together a wish list. For addressing item 1, it would be nice if we could create a WidgetFactory by passing a parameter list to an AbstractFactory template: typedef AbstractFactory<Window, Button, ScrollBar> WidgetFactory; For addressing item 2, we need a template-like invocation for various CreateXxx functions, such as Create<Window>(), Create<Button>(), and so on. Then we can invoke it from generic code:
template <class T>
T* MakeRedWidget(WidgetFactory& factory)
{
T* pW = factory.Create<T>(); // aha!
pW->SetColor(RED);
return pW;
}
However, we cannot fulfill these needs. First, the typedef for WidgetFactory above is not possible because templates cannot have a variable number of parameters. Second, the template syntax Create<Xxx>() is not legal because virtual functions cannot be templates. By this point, you should see what good abstraction and reuse opportunities we have, and how badly we are constrained in exploiting these opportunities due to language limitations. Typelists make it possible to create generic Abstract Factories and much more. |
I l@ve RuBoard |