Professional C__ - Marc Gregoire [335]
If you attempt to instantiate a template with a type that does not support all the operations used by the template in your particular program, the code will not compile, and the error messages will almost always be quite obscure. However, even if the type you want to use doesn’t support the operations required by all the template code, you can exploit selective instantiation to use some methods but not others. For example, if you try to create a grid for an object that has no assignment operator, but you never call setElementAt() on that grid, your code will work fine. As soon as you try to call setElementAt(), however, you will receive a compilation error.
Distributing Template Code between Files
Normally you put class definitions in a header file and method definitions in a source file. Code that creates or uses objects of the class #includes the header file and obtains access to the method code via the linker. Templates don’t work that way. Because they are “templates” for the compiler to generate the actual methods for the instantiated types, both template class definitions and method definitions must be available to the compiler in any source file that uses them. There are several mechanisms to obtain this inclusion.
Template Definitions in Header Files
You can place the method definitions directly in the same header file where you define the class itself. When you #include this file in a source file where you use the template, the compiler will have access to all the code it needs.
Alternatively, you can place the template method definitions in a separate header file that you #include in the header file with the class definitions. Make sure the #include for the method definitions follows the class definition; otherwise the code won’t compile.
template class Grid { // Class definition omitted for brevity }; #include "GridDefinitions.h" Code snippet from Grid\MethodsInSeparateHeader\Grid.h Any client that wants to use the Grid template needs only to include the Grid.h header file. This division helps keep the distinction between class definitions and method definitions. Template Definitions in Source Files Method implementations look strange in header files. If that syntax annoys you, there is a way that you can place the method definitions in a source file. However, you still need to make the definitions available to the code that uses the templates, which you can do by #includeing the method implementation source file in the template class definition header file. That sounds odd if you’ve never seen it before, but it’s legal in C++. The header file looks like this: template class Grid { // Class definition omitted for brevity }; #include "Grid.cpp" Code snippet from Grid\MethodsInSource\Grid.h When using this technique, make sure you don’t add the Grid.cpp file to your project, because it is not supposed to be, and cannot be compiled separately; it should only be #included in a header file. You can actually call your file with method implementations anything you want. Some programmers like to give source files that are included an .inl extension, for example Grid.inl. The pre-C++11 standard actually defined a way for template method definitions to exist in a source file, which does not need to be #included in a header file. You use the export keyword to specify that the template definitions should be available in all translation units (source files). However, this is not allowed anymore in C++11. Template Parameters In the Grid example, the Grid template has one template parameter: the type that is stored in the grid. When you write the class template, you specify the parameter list inside the angle brackets, like this: template