I was recently asked about the issues of using C++ templates in deeply embedded systems (i.e. not Linux, etc.)
"But, it might increase footprint of code. Because compiler will add auto generated code for template. e.g. let we define two variable SimpleHashTable<int,string> s1 and SimpleHashTable<float,string> s2. Then they generate two different classes from template 1> with int, string 2> with float, string. Hence it is trade-off to use template in code base. I am from embedded background so we don't use much of template."
"But, it might increase footprint of code. Because compiler will add auto generated code for template.
e.g. let we define two variable SimpleHashTable<int,string> s1 and SimpleHashTable<float,string> s2.
Then they generate two different classes from template
1> with int, string
2> with float, string.
Hence it is trade-off to use template in code base. I am from embedded background so we don't use much of template."
The writers concerns about increased footprints with templates are well founded, and have been a major reason many embedded programmers have avoided templates.
Going back to early cross-compilers supporting templates, then the memory footprint was an issue, however things have move on significantly and modern compilers have some very neat tricks up their sleeves.
First, you are correct that given the two different instantiations there will be two versions of the code base in the image. However, modern compilers do something called “instantiation-on-demand or lazy-instantiation”, meaning that code is only ever generated if that member function is actually called. So instantiation of a large template class doesn’t automatically lead to a large code base. Also, a historic problem with templates, was that if, for example, we instantiated the SimpleHashTable<int, string> in two different .cpp files, we would get copies of the code in both .o files; this no longer happens and there will only be one instance of the instantiated code for a concrete type. This also means there is no need for link-time optimization and there is never any redundant generated code (compile-time optimization vs. link-time optimization).
Second, the template code generators are very smart. Template code is about algorithmic abstractions and container management. When writing template code we make requirements of type-traits rather than concrete types (e.g. to use this template code a type must support operator<). If the type-traits match two instantiated types, and their memory size match, then a compiler may reuse and existing template instantiation (this is most common with pointers as template parameters). Given you example of SimpleHashTable<int,string> s1 and SimpleHashTable<float,string> s2, the complier will generate code for s1. When it looks at the s2 instantiation it may be able to reuse the code generated for s1 as, for example on an ARM core, sizeof(int) == sizeof(float).
SimpleHashTable<int,string> s1
SimpleHashTable<float,string> s2
sizeof(int) == sizeof(float).
I’d say there are two separate issues with templates and deeply embedded systems (i.e. constrained memory system with virtual memory management).
First, using existing templates, i.e. the STL; the issue here is that, by default, the STL containers allocate memory dynamically for the free-store/heap. So to use them safely you need to provide your own allocators. It’s also worth noting that there have been major steps forward in the C++11 STL (such as an array container and static initialization) which makes them very useable for embedded.
Second, writing your own maintainable templates is non-trivial. It’s very easy to get carried away with templates (they are very cool after all), but can end up being used inappropriately. This then leads to maintenance issues.
Remember, templates, generally, should be used only for library style code, not application level code.
The use of templates and the associated issues in embedded systems is covered extensively in the Feabhas training course Advanced C++for Embedded Systems.