The Problem with C++ Templates
C++ has evolved as a language that encompasses many modern programming techniques. In this way, C++ has managed to stay relevant, despite the many issues that it may have compared to safer languages such as Java or C#. In C++, one can decide the set of features that will be used from within a large set of alternatives. If you’re inclined to do so, you could use only an strictly object oriented style, or maybe a functional oriented style, if that suits you better. Moreover, with the additions proposed in C++11, you can even use closures to make your coding style more functional.
Among the features provided by C++, one that it pioneered was the use of template programming. While templates provide some of the features allowed by Lisp macros, they also enforce type safety. This safety helps a lot when working with a language such as C++, which is so strict about the correct use of types.
Templates and the Type System
Templates have been crucial to provide some features previously missing in C++. For example, the idea of generic containers can only be possible with some kind of type instantiation. Even other languages such as Java and C# had to introduce template-like features in order to cope with the problem of generic containers.
While templates are very important, they also bring a severe burden into the language. Templates operate at compile time, making decisions about how to instantiate a particular type given the options allowed by the available template code. This kind of decision is not only powerful, but also time consuming.
The trouble with using templates more generally is that they are not very programmer friendly. While templates solve important problems, they are also hard to use and design. Here follow a few issues that I believe are of high importance.
C++ provides header files as a method for creating modules and explicitly separating interface from implementation. However, templates make this separation harder to achieve. When a compiler creates code from a template, it needs not only access to the interface, but also to the whole definition of the template. The reason is that much of the required information used by a template is stored in its definition. For example, what are the methods accessed in a particular type? These properties are needed by the compiler to decide if a template can be expanded or not.
In the past, there were some proposals to fix the module separation issue. Using the external keyword along with a template declaration was one of the options proposed by the ANSI committee, but it was never implemented by the major compilers, and nowadays it has been deprecated. It seems that there will be no solution in foreseeable future, so the only thing it remains for software engineers is to minimize the use of templates unless they are really required.
Another issue that is a consequence of the above is the compilation time necessary to use templates. Since all of the template must be accessible to the compiler, if no additional calculations were necessary we would still have a severe burden by including templates in a project. However, remember that templates provide a sub-language within C++ that is known to be Turing-complete. This means that badly behaving templates can very well turn into infinite loops, among other issues that need to be debugged — at compile time. This means that using templates requires a lot of care from the part of the programmer, since it can result both in compile-time as well as run-time bugs.
But it doesn’t stop there. Templates also have a very particular way to bloat executables, which can turn a simple looking solution into a nightmare of slow linking times. Templates have this tendency to generate additional code for each instantiation for a concrete type. For example, for every compilation unit, in the first time you create a std::vectorthe compiler will try to instantiate yet another version of std::vector, even if there already is a version of that template for each compilation unit of the program. This is not such a huge problem because a linker will check all existing object files and remove duplicate versions of template instantiations. The real problem is that this process takes time. In a big C++ project this can consume from a few seconds to several minutes.
The other issue, however, happens when the method described above doesn’t remove all the multiple copies of a template. In fact, there might be thousands of legitimate instantiations of a template in a single program. For example, if you have thousands of types (which is common in a C++ project), you may also have thousands of different instantiations of std::vector, and even millions of instantiations of std::map(not common, but possible).
Then you have design issues that make this even worse. I once worked in a project that had a template for String, where n was the maximum size of the string. The designers of this template thought they were doing a good service, until you realize that there is a copy of this template for each of the hundreds of string sizes used in the project. Also, using a template like this induces the creation of related templates, so you end up having ImmutableString, etc.
I just scratched the surface of possible problems when using templates in C++. My goal is not to discourage the use of existing templates, such as the STL, but to caution against the indiscriminate use of templates in C++ projects. I personally think that you should use templates only to go around limitations in C++, because that is why they were originally created. Trying to use templates as a normal programming paradigm unleashes more problems, as we just mentioned, than it can possibly solve.
C++ Templates: The Complete Guide: I like this book because it covers all the information you need to become knowledgeable about templates. The book starts from the basics, but also discusses advanced techniques for template writers.
About the Author
Carlos Oliveira holds a PhD in Systems Engineering and Optimization from University of Florida. He works as a software engineer, with more than 10 years of experience in developing high performance, commercial and scientific applications in C++, Java, and Objective-C. His most Recent Book is Practical C++ Financial Programming.