You can also manually instantiate classes and static data members. When explicitly instantiating a class, all member functions for the requested specialization are instantiated, except any that may have been explicitly instantiated previously. Using only implicit instantiation has the advantage here: only member functions that actually get called are instantiated. Explicit instantiation is intended for large projects in which a hefty chunk of compilation time can be avoided. Whether you use implicit or explicit instantiation is independent of which template compilation you use, of course; you can use manual instantiation with either the inclusion model or the separation model (discussed in the next section).
The separation model
The separation model of template compilation allows you to separate function template definitions or static data member definitions from their declarations across translation units, just like you do with ordinary functions and data, by
Historically, the inclusion model was the first to experience widespread commercial use. Part of the reason for that was that the separation model was not well specified until late in the standardization process. It turns out that the inclusion model is the easier of the two to implement. All C++ compilers support the inclusion model. A lot of working code was in existence long before the semantics of the separation model were finalized.
The technical aspect reflects the fact that the separation model is difficult to implement. In fact, as of summer 2003 only one compiler front end (EDG) supports the separation model, and at the moment it still requires that template source code be available at compile time to perform instantiation on demand. Plans are in place to use some form of intermediate code instead of requiring that the original source be at hand, at which point you will be able to ship "pre-compiled" templates without shipping source code. Because of the lookup complexities explained earlier in this chapter (about dependent names being looked up in the template definition context), a full template definition still has to be available in some form when you compile a program that instantiates it.
The syntax to separate the source code of a template definition from its declaration is easy enough. You use the export keyword:
// C05:OurMin2.h
// Declares min as an exported template
//! (Only works with EDG-based compilers)
#ifndef OURMIN2_H
#define OURMIN2_H
export template
const T&);
#endif
Similar to inline or virtual, the export keyword need only be mentioned once in a compilation stream, where an exported template is introduced. For this reason, we need not repeat it in the implementation file, but it is considered good practice to do so:.
// C05:OurMin2.cpp
// The definition of the exported min template
//! (Only works with EDG-based compilers)
#include "OurMin2.h"
export
template
return (a < b) ? a : b;
} ///:~
The UseMin files used previously only need to be updated to include the correct header file (OurMin2.h), and the main program need not change at all. Although this appears to give true separation, the file with the template definition (OurMin2.cpp) must still be shipped to users (because it must be processed for each instantiation of min) until such time as some form of intermediate code representation of template definitions is supported. So while the standard does provide for a true separation model, not all of its benefits can be reaped today. Only one family of compilers currently support export (those based on the EDG front end), and these compilers currently do not exploit the potential ability to distribute template definitions in compiled form.
Summary
Templates have gone far beyond simple type parameterization! When you combine argument type deduction, custom specialization, and template metaprogramming, C++ templates emerge as a powerful code generation mechanism.
One of the weaknesses of C++ templates we skipped in this chapter is the difficulty in interpreting compile-time error messages. When you’re not used to it, the quantity of inscrutable text spewed out by the compiler is quite overwhelming. If it’s any consolation, C++ compilers have actually gotten a lot better about this. Leor Zolman has written a nifty tool STLFilt, that renders these error messages much more readable by extracting the useful information and throwing away the rest.[78]