|
Boost : |
From: timatdvc (timw_at_[hidden])
Date: 2002-02-18 09:26:45
My colleagues and I have been working on some concepts and techniques
that would be useful in developing configurable active libraries. I
wanted to present them here, where many of related ideas have been
discussed before and where these techniques might be most useful.
The main idea is to combine the strengths of policy-based design and
generative programming. Policies allow many possible configurations
of a component, while a generator's goal is to automate the
construction of components based on user-supplied options. In C&E,
they present the GenVoca approach as a possible architectural model.
Policies, we feel, are much provide a more tangible decomposition of
a given problem. Combining these approaches may be able to give the
best of both worlds.
This approach would be applicable for large libraries or components
where the number of policies becomes unwieldy. With a combined
approach, clients specify abstract options using the "grammar" of the
domain/problem space (rather than the implementation/solution space,
where policies sort of live). The generator then uses these options
to select the policies needed to meet the client's requirement.
Here's a bit of code to show how it would look from a user's point of
view. First, a user would construct the list of options that would
be passed to the generator utilizing some typelist mechanism:
// Construct a list of options for the generator
typedef ConstructOptionList<
SetOptionType <AllocatorOption, std::allocator<int*> >,
SetOptionValue<OptimizedUseOption, OPTIMIZED_GENERAL>,
SetOptionValue<OwnershipOption, OWN_REF>
>::Type
OptionList;
// Provide the options to the generator to make the requested type
typedef LIBRARY_GENERATOR<OptionList>::Type GeneratedLibraryType;
As you can see in this example, rather than have the generator take
many individual template parameters (one for each option), a typelist
is passed that contains all of the selected options. The
LIBRARY_GENERATOR then searches the typelist for each option category
(using some simple metaprogramming, so this happens at compile-
time). If an option category is found the provided type or value is
selected, otherwise the default is used. In this way, any option
default can be overridden in any order, unlike the approaches
outlined in Generative Programming or in Modern C++ Design where each
template parameter's position in the argument list is "hardwired".
Using the typelist makes selecting various combinations and
overriding options significantly simpler and less verbose.
Options passed to the generator can either be enumeration values
(selected via SetOptionValue), or types (selected via
SetOptionType). The first parameter is either a struct tag (in the
case of type options), or an enumeration type (in the case of value
options). Value options can be used to select an abstract option
that results in the selection of a generator-defined policy. Type
options can be used to provide the generator with "custom" user-
supplied policies. Extending the car factory metaphor used in
Generative Programming, this is a lot like telling the factory, "I
want a fast car with a manual transmission (value options), but I
want you to install my custom stereo and these special tires (type
options). This would result in a car with a V8 and the correct
transmission (along with everything needed to make that combination
work), as well as the custom options provided by the client.
As described above, the generator searches the option typelist for
each type of option that can be set by a client. Using that
information, appropriate policies are selected and passed to the
actual policy-based library class, which becomes typedefed as "Type"
inside the generator.
Incidentally, I stumbled onto an interesting construct that can help
to limit which option values can be selected. I'm sure it's been
done before, but I though you might be interested. The
SetOptionValue is defined as follows:
template <class Option_, Option_ Value_>
struct SetOptionValue
{
typedef Option_ Option;
enum { Value = Value_ };
};
What is so cool about this is that if Option_ is an enumeration type,
then Value_ *MUST* be one of the symbolic constants defined by that
enumeration. It's a neat trick that forces enumerated value options
to only be set to one of symbolic values specified by the enumeration
type.
Anyway, the value I see in applying generative programming to a
policy based design is that a very complex, highly configurable
library can expose a very simple and expressive interface that allows
options to be selected using domain language (but still allowing
further policy-based customization). I hope you find this
interesting; your opinions would be greatly appreciated, of course.
And if you have any questions about the details of the approach, I
would, of course, be happy to provide more information.
Tim Woodard
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk