From time to time we have to use objects with static storage duration. The most famous pattern Singleton is often implemented this way. Sometimes static objects should be grouped together to form a container of related objects. The static_list class template is served for this purpose.
Imagine that you are responsible for implementation of several spell checkers
for your favorite open-source e-mail client. After reading a book about object
oriented design you decided to define abstract SpellChecker
class
and special make-function which creates instance of concrete spell checker class
for a given language:
class SpellChecker { public: virtual void checkSpelling(class Text&) = 0; virtual ~SpellChecker() = 0; // ... }; std::auto_ptr<SpellChecker> createSpellChecker(const std::string& language);
The design looks good. User of this code will be happy. All she needs is
to call createSpellChecker
with required language as a parameter.
There is also other group of users you should care of. These are developers who will
implement concrete spell checker classes. Although these classes can be developed
independently their all should be connected with createSpellChecker
function. Some mechanism to register make-function for a given language is needed.
Additionally, it would be nice to have container-like interface to access registered
entities.
First of all, lets define a type holding language name and a pointer to correspondent make-function:
typedef SpellChecker* (*MakeFunction)(); typedef std::pair<char const*,MakeFunction> NamedMakeFunction;
Every concrete class derived from SpellChecker
shall let others know
about its make-function by somehow registering a NamedMakeFunction
object.
Details followed.
Now, let's turn our attention to static_list
class template. It is used
to insert elements during static initialization and to access elements afterwards.
In our case, access to NamedMakeFunction
objects can be made through
this type:
typedef static_list<NamedMakeFunction> MakeFunctionList;
Insertion of new object is very simple. All you need is to define special
object with static storage duration. Exactly one object for one element in the list.
For example, if you have implemented createSpellChecker_en
make-function you could just insert the following code into a source file
below the function definition:
namespace { MakeFunctionList::insert element(NamedMakeFunction("en", createSpellChecker_en)); }
This code inserts an element into MakeFunctionList
during
dynamic phase of static initialization. When static initialization is completed
everyone has access to your element through iterators.
Like other containers MakeFunctionList
has begin
and end
functions to get the range of elements.
Unlike others these functions are static members of static_list
because there is only one list of NamedMakeFunction
elements in a program.
Therefore, a range of elements can be represented as shown in a following code snipset:
int size = std::distance(MakeFunctionList::begin(), MakeFunctionList::end()); // range assert(MakeFunctionList::size() == size); // size() function is faster then distance
For your convenience, static_list
has also classic interface:
MakeFunctionList l; int size = std::distance(l.begin(), l.end());
Copy constructor for static_list
is also provided although
it doesn't copy list elements. All static_list
objects refer
to one list. It's worth to note that static_list
gives you
read-only access to the elements using forward iterator.
Consider copying the content into other data structures should you need
more advanced access.
Taking all this in mind, createSpellChecker
function could
be written as follow:
std::auto_ptr<SpellChecker> createSpellChecker(const std::string& language) { MakeFunctionList l; for(MakeFunctionList::const_iterator it = l.begin(); it != l.end(); ++it) { NamedMakeFunction const& element = *it; read-only if(element.first == language) { MakeFunction makeFunc = element.second; return std::auto_ptr<SpellChecker>(makeFunc()); } } return std::auto_ptr<SpellChecker>(); }
Implementation of a function returning a list of languages with spell checking available is left as exercise for a reader.