Using Exported Templates
Problem
You want to build a program that uses exported templates, meaning that it declares templates in headers with the export keyword and places template implementations in .cpp files.
Solution
First, compile the .cpp files containing the template implementations into object files, passing the compiler the command-line options necessary to enable exported templates. Next, compile and link the .cpp files that use the exported templates, passing the compiler and linker the command-line options necessary to enable exported templates as well as the options to specify the directories that contain the template implementations.
The options for enabling exported templates are given in Table 1-39. The options for specifying the location of template implementations are given in Table 1-40. If your toolset does not appear in this table, it likely does not support exported templates.
Toolset |
Script |
---|---|
Comeau (Unix) |
export, -A or strict |
Comeau (Windows) |
export or A |
Intel (Linux) |
-export or -strict-ansi[22] |
[22] Versions of the Intel compiler for Linux prior to 9.0 used the option -strict_ansi.
Toolset |
Script |
---|---|
Comeau |
template_directory= |
Intel (Linux) |
-export_dir |
For example, suppose you want to compile the program displayed in Example 1-27. It consists of three files:
- The file plus.hpp contains the declaration of an exported function template plus( ).
- The file plus.cpp contains the definition of plus( ).
- The file test.cpp includes the declarationbut not the definitionof plus( ), and defines a main( ) function that uses plus( ).
Example 1-27. A simple program using exported templates
plus.hpp: #ifndef PLUS_HPP_INCLUDED #define PLUS_HPP_INCLUDED export template T plus(const T& lhs, const T& rhs); #endif // #ifndef PLUS_HPP_INCLUDED plus.cpp: #include "plus.hpp" template T plus(const T& lhs, const T& rhs) { return rhs + lhs; } test.cpp: #include #include "plus.hpp" int main( ) { std::cout << "2 + 2 = " << plus(2, 2) << " "; }
To compile plus.cpp to an object file plus.obj using Comeau on Unix, change to the directory containing plus.cpp, plus.cpp, and test.cpp, and enter the following command:
$ como -c --export plus.cpp
This command also generates a file plus.et describing the template implementations contained in plus.cpp.
|
Next, compile test.cpp to an object file test.obj, as follows:
$ como -c --export test.cpp
Finally, link the executable test.exe:
$ como --export -o test test.obj
The last two commands could also have been combined:
$ como --export -o test test.cpp
You can now run test.exe:
$ ./test 2 + 2 = 4
Alternatively, suppose that the files plus.hpp and plus.cpp are in a directory named plus, while test.cpp is in a sibling directory test. To compile and link test.cpp, change to the directory test and enter:
$ como --export --template_directory=../plus -I../plus -o test test.cpp
Discussion
C++ supports two models for supplying the definitions of function templates and static data members of class templates: the inclusion model and the separation model. The inclusion model is familiar to all programmers who regularly use C++ templates, but often seems unnatural to programmer accustomed to writing nontemplated code. Under the inclusion model, the definition of a function templateor of a static data member of a class templatemust be included by each source file that uses it. By contrast, for nontemplated functions and data it is sufficient for a source file simply to include a declaration; the definition can be placed in a separate .cpp file.
The separation model is closer to the traditional manner of organizing C++ source code. Templates declared with the export keyword do not need to have their definitions included by source files that use them; instead, the definitions can be placed in separate .cpp files. The parallel with traditional source code organization is not exact, though, because even though code that uses an exported template does not need to include its definition, it still depends on the definition in some subtle ways.
The separation model offers several potential benefits:
Reduced compilation times
Compilation time may improve with the separation model because a template's definition needs to be scanned less frequently and because the separation modules reduce dependencies between modules.
Reduced symbolic "pollution"
Names of functions, classes, and data used in a template's implementation file can be completely hidden from code that uses the template, reducing the possibility of accidental name clashes. In addition, the author of a template implementation can worry less about accidental clashes with names from the source files that use the template.
The ability to ship precompiled template implementations
In theory, under the separation mode, a vendor could ship template implementations that have been precompiled into a binary format somewhere between C++ source code and ordinary object files.
All three potential advantages of the separation model are controversial. First, while some users have reported reduced compile times, the separation model can also lead to longer compile times in some cases. At the moment, there is insufficient data to make a definitive judgment. Second, while the separation model does reduce some forms of symbolic pollution, the language rules necessary to support the separation model, particularly the notion of two-phase lookup , have complicated the way templated code is writteneven when using the inclusion modeland have had some unintended consequences. Third, all existing implementations of the separation model are based on the EDG frontend, and EDG has not yet provided any means to compile source files containing exported template implementations into binary files that can be shipped in lieu of the source.
There was an effort in 2003 to remove exported templates from future versions of the C++ standard, but it failed. Consequently, exported templates are a permanent part of the C++ language, and you should learn to use them.
See Also
Recipe 1.25