containers; iterators act like pointers (but may be objects instead); containers and algo-
rithms accept function pointers and function objects with equal aplomb; and library clients
may extend the library without having to inherit from any base classes or redefine any
virtual functions, made me feel—as I had when I read Barton and Nackman’s work—like
I knew almost nothing about templates.
So I wrote almost nothing about them in More Effective C . How could I? My under-
standing of templates was still at the containers-of-
T stage, while Barton, Nackman,
Stepanov, and others were demonstrating that such uses barely scratched the surface of
what templates could do.
In 1998, Andrei Alexandrescu and I began an e-mail correspondence, and it was not
long before I recognized that I was again about to modify my thinking about templates.
Where Barton, Nackman, and Stepanov had stunned me with what templates could do,
however, Andrei’s work initially made more of an impression on me for how it did what
it did.
One of the simplest things he helped popularize continues to be the example I use
when introducing people to his work. It’s the
CTAssert template, analogous in use to
the assert macro, but applied to conditions that can be evaluated during compilation.
Here it is:
template<bool> struct CTAssert;
template<> struct CTAssert<true> {};
That’s it. Notice how the general template, CTAssert, is never defined. Notice how there is
a specialization for
true, but not for false. In this design, what’s missing is at least as im-
portant as what’s present. It makes you look at template code in a new way, because large
portions of the “source code” are deliberately omitted. That’s a very different way of think-
ing from the one most of us are used to. (In this book, Andrei discusses the more sophisti-
cated
CompileTimeChecker template instead of CTAssert.)
Eventually, Andrei turned his attention to the development of template-based imple-
mentations of popular language idioms and design patterns, especially the GoF* patterns.
This led to a brief skirmish with the Patterns community, because one of their fundamen-
tal tenets is that patterns cannot be represented in code. Once it became clear that Andrei
was automating the generation of pattern implementations rather than trying to encode pat-
terns themselves, that objection was removed, and I was pleased to see Andrei and
one of the GoF (John Vlissides) collaborate on two columns in the C Report focusing on
Andrei’s work.
In the course of developing the templates to generate idiom and pattern implementa-
tions, Andrei was forced to confront the variety of design decisi
ons that all implementers
face. Should the code be thread safe? Should auxiliary memory come from the heap, from
the stack, or from a static pool? Should smart pointers be checked for nullness prior to
dereferencing? What should happen during program shutdown if one Singleton’s de-
structor tries to use another Singleton that’s already been destroyed? Andrei’s goal was to
offer his clients all possible design choices while mandating none.
xii
Foreword
* “GoF” stands for “Gang of Four” and refers to Erich Gamma, Richard Helm, Ralph Johnson, and John
Vlissides, authors of the definitive book on patterns, Design Patterns: Elements of Reusable Object-Oriented Software
(Addison-Wesley, 1995).