Templates
are a good candidate for coping with combinatorial behaviour's because they
generate code at compile time based on the types provided by the user.
Class
templates are customizable in ways not supported by regular classes. If you
want to implement a special case, you can specialize any member functions of a
class template for a specific instantiation of the class template. For example,
if the template is SmartPtr<T>, you can specialize any
member function for, say, SmartPtr<Widget>.
This gives you good granularity in customizing behaviour.
Furthermore,
for class templates with multiple parameters, you can use partial template
specialization. Partial template specialization gives you the ability to
specialize a class template for only some of its arguments. For example, given
the definition
template
<class T, class U> class SmartPtr { ... };
you
can specialize SmartPtr<T, U> for Widget
and any other type using the following syntax:
template
<class U> class SmartPtr<Widget, U> { ... };
The
innate compile-time and combinatorial nature of templates makes them very
attractive for creating design pieces. As soon as you try to implement such
designs, you stumble upon several problems that are not self-evident:
1.
You cannot specialize structure. Using templates
alone, you cannot specialize the structure of a class (its data members). You can specialize
only functions.
2.
Specialization of member functions does not scale. You can
specialize any member function of a class template with one template parameter,
but you cannot specialize individual member functions for templates with
multiple template parameters. For example:
template <class T>
class Widget
{
void Fun() { .. generic
implementation ... }
};
// OK: specialization of a
member function of Widget
template <>
Widget<char>::Fun()
{
... specialized
implementation ...
}
template <class T,
class U> class Gadget
{
void Fun() { .. generic
implementation ... }
};
// Error! Cannot partially
specialize a member class of Gadget
template <class U>
void Gadget<char, U>::Fun()
{
... specialized
implementation ...
}
3.
The library writer cannot provide multiple default
values. At
best, a class template implementer can provide a single default implementation
for each member function. You cannot provide several defaults for a
template member function.
Now compare the
list of drawbacks of multiple inheritance with the list of drawbacks of
templates. Interestingly, multiple inheritance and templates foster
complementary trade-offs. Multiple inheritance has scarce mechanics; templates
have rich mechanics. Multiple inheritance loses type information, which abounds
in templates. Specialization of templates does not scale, but multiple inheritance
scales quite nicely. You can provide only one default for a template member
function, but you can write an unbounded number of base classes.
This analysis
suggests that a combination of templates and multiple inheritance could
engender a very flexible device, appropriate for creating libraries of design
elements.
No comments:
Post a Comment