I l@ve RuBoard Previous Section Next Section

3.1 The Need for Typelists

Sometimes 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:

  1. If you cannot take a stab at generalizing the fundamental concept, you won't be given a chance to generalize the concrete instances of that concept. This is a crucial principle. If the essence escapes generalization, you continue to struggle with the concrete artifacts of that essence. In the Abstract Factory case, although the abstract base class is quite simple, you can get a nasty amount of code duplication when implementing various concrete factories.

  2. You cannot easily manipulate the member functions of WidgetFactory (see the previous code). A collection of virtual function signatures is essentially impossible to handle in a generic way. For instance, consider this:

    
    
    template <class T>
    
    
    T* MakeRedWidget(WidgetFactory& factory)
    
    
    {
    
    
       T* pW = factory.CreateT(); // huh???
    
    
       pW->SetColor(RED);
    
    
       return pW;
    
    
    }
    
    
    

    You need to call CreateWindow, CreateButton, or CreateScrollBar, depending on T being a Window, Button, or ScrollBar, respectively. C++ doesn't allow you to do this kind of text substitution.

  3. Last, but not least, good libraries have the nice side effect of putting aside endless debates about naming conventions (createWindow, create_window, or CreateWindow?) and little tweaks like that. They introduce a preferred, standardized way of doing things. Abstracting, well, Abstract Factory would have this nice side effect.

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 Previous Section Next Section