Separate compilation and exporting template definitions

This has been a fraught battleground within the committee for several years with no consensus on how best to provide a standard for separation of template declarations and definitions.

Some background information is in order! The archetypal C++ compiler used to be AT&T's Cfront. It allowed template declarations to be placed in header files and the corresponding definitions to be placed in source files. At link time it would then search for the template definitions to satisfy any unresolved symbols in the rest of the program and compile the template instantiations by creating a synthetic compilation context: a file containing includes of the all the necessary headers and an include of the template source file. This meant that the template definition files did not need to include any headers and so might well not be compilable independently.

However, this system was slow and easily confused (because the repository into which Cfront stores its information can get out of step with the source code that relies on it). When PC vendors started providing templates in C++ compilers, they chose to require that template definitions were included in header files and used "smart link" technology to remove duplicate function definitions from the resulting executable image.

Several UNIX vendors then decided to adopt this approach as well, or some variant on one of these two approaches. This made it almost impossible to write template code in any portable way.

Unfortunately, the "include everything" approach was not sanctioned by the then current C++ draft standard (because the duplication of definitions was ill-formed and the draft did not support the notion of throwing away excess definitions). So the committee voted to specify the linkage of template definitions and, along with a few other minor tweaks, allow the include everything approach to be conforming.

This wasn't much of a solution as many vendors still didn't support separate compilation of template definitions and didn't want to either. After a while, these vendors became quite vocal about removing the wording from the draft that allowed separate compilation. This was strongly resisted by other members of the committee.

In Santa Cruz (March '96), the ANSI committee voted 2-1 in favour of a proposal by these vendors to remove support for separate compilation. The ISO representatives could not agree on a course of action so the proposal was tabled until the July meeting.

During the intervening time, Silicon Graphics staff worked very hard on defining a set of restrictions that served two purposes:
- the restrictions made templates easier to implement and use
- they made efficient implementation of separate compilation possible

The SGI proposal was adopted in two parts in Stockholm (July '96). The first part was non-controversial as it made several small improvements to templates regardless of the source code model in use. The second part was to specifically support separate compilation by adding a keyword export that could be used to indicate a template definition should be "available" outside the translation unit in which it appeared.

The result is that the C++ Standard supports both "separation" and "inclusion" as source code organisations.


The new export keyword can be used like this:
	// templ.H
	export template<typename T>
	void f(T t);

	template<typename T>
	void g(T t) { ... }

	// templ.C
	#include <templ.H>

	template<typename T>
	void f(T t) { ... }
The template g has its definition included in every translation unit in which it is referenced - it is not separately compiled. The template f however has its definition in just one translation unit but can be referenced in any translation unit that includes just the declaration. When resolving template instantiations, the compiler must (somehow) find templ.C and process the definition of f.

The Standard does not specify how the compiler finds the source file. Possible conforming implementations include:
- "magic": the compiler just finds it!
- the compiler requires that you compile templ.C prior to instantiations of f
- the compiler requires that you tell it where to find f using some extra-lingual mechanism

This means that the source code can be portable although the build mechanism may differ between platforms.

Note one important side effect of these changes: the file containing the template definition should be a valid, compilable translation unit.


By suitable use of include files, you can organise code in such a way that users have the choice of "inclusion" or "separation" of your libraries.

	// templ.H
	// declarations of templates:
	template<typename T>
	class Thing
	{
	  public:
	    void g();
	    //...
	};
	template<typename T>
	void f(T t);
	// end templ.H

	// templdef.H
	// declarations (included) and definitions
	// of templates:
	#include <templ.H>

	template<typename T>
	void Thing<T>::g() { ... }

	template<typename T>
	void f(T t) { ... }
	// end templdef.H

	// inclusion.C
	// this model includes all the definitions:
	#include <templdef.H>
	// ...use Thing and f...

	// separation.C
	// this model expects the compiler to find
	// the definitions:
	#include <templ.H>
	// ...use Thing and f...

	// templ.C
	// this needs to be compiled and linked
	// with separation.C:
	export template<typename T> class Thing;
	export template<typename T> void f(T t);
	#include <templdef.H>
A template class declared export means that all its member function definitions are exported as well.