12

I never understood this issue with templates. For me instantiating a method multiple types for different type of parameter is same as implementing the same in terms of function overloading. If this is the case how template causes the code bloat or exceeds the binary size to a certain limit. Please bring clarity into this.

Sometimes I am unsure whether to use templates or function overloading. Template code bloat is the problem I have heard of, but never understood.

Jan Schultke
  • 17,446
  • 6
  • 47
  • 96
Chris
  • 229
  • 1
  • 2
  • 11

2 Answers2

9

How does template cause the code bloat in C++?

Code bloat occurs because compilers generate code for all templated functions in each translation unit that uses them. Back in the day, the duplicate code was not consolidated, which resulted in "code bloat". These days, the duplicate code can be removed at link time.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
Captain Obvlious
  • 19,754
  • 5
  • 44
  • 74
  • Since templates have to be header only, will function templates/member function templates be inlined? – Steve Lorimer Sep 30 '14 at 03:54
  • 1
    Templates do not _have_ to be in headers only although it is usually the most effective choice. You can place the function declarations or class definitions in the header file, the function definitions in a source file and use [explicit template instantiation](http://www.cplusplus.com/articles/1C75fSEw/) to ensure the code is generated. Whether they are linked or not depends if they are actually _referenced_ (i.e. instantiated, called, or used in a vtable). – Captain Obvlious Sep 30 '14 at 14:22
  • Neat, didn't know about that, but for many use cases as you mention, having the code in the header is the most effective choice. In this case will the functions be inlined? – Steve Lorimer Sep 30 '14 at 23:31
  • 1
    These days it's usually up to the compiler as many will ignore the `inline` keyword and decide on their own if it should be inlined or not. Function templates do not have to be declared `inline` as they follow a more relaxed ODR specification (i.e. multiple definitions can exist as long as they are identical). Member functions defined inside of a class definition are automatically specified as `inline` to satisfy ODR (even if the compiler decided not to inline). There are plenty of questions about this on SO with answers that go into much greater detail. – Captain Obvlious Oct 01 '14 at 14:01
  • 2
    No this is a wrong answer, at least partial wrong. Most compilers especially in the old days did not output the templates at all in object files. Instead at linking time the "linker" called back the compiler to generated the required code, and only do it once. This was done because compile time was significant more precious in the time of 50 Mhz single core workstations. Templating was forbidden in many projects for this reason. The code bloat from the past is still the same reason for the code bloat of 2017: there is no type erasure. – Lothar Dec 17 '17 at 10:38
  • 2
    And with type erasure i mean casting pointers to void* or to string of bytes and then perform the operations which generate the same code for all instantiations exactly once. Sometimes in release builds the linker is able to see that the functions generate the same assembly code and therefore remove duplicates. This is what is called type erase in modern days. – Lothar Dec 17 '17 at 10:39
  • You are wrong about duplicate code removed at link time. Today projects often spread across many DLLs, and linker cannot merge same functions across different DLLs. So if you have heavily-templated code across 20 DLLs, be ready to see all STL code duplicated 20 times. Besides, when compiler inlines the code from a header into call site, it also increases total code size in many cases. Compiler heuristics are not perfect in this regard. When binary size reaches dozens of MB, it can become a problem. – stgatilov Mar 10 '20 at 06:16
3

Templates are they are not final code cannot be compiled and linked so templates are lost when compiling is done, and the final object file does not contain any template definitions, only the instantiated methods.

This comes with a consequence we are all used to: templates libraries are header only. They are just like static functions in this regard, each translation unit uses their own copy of the same template function. In C++11 you can prevent this with using extern templates, but that's far from automatic, and usually it doesn't even worth the time.

The second issue is that unlike using unions, void * pointers or object inheritance, which are tools that reuse existing code, templates are stupid, and they will generate new code, even if it's the same for any type.

for example:

void * malloc(size_t int);

template<class T> T * talloc(size_t int);

the second function will generate different code for all T types, even though the generated code will be the same.

Of course the compiler will also try and save on the genarated functions. For each class only the functions that are actually used in that translation unit will be generated for any template parameters.

But since the virtual table needs the addresses of all virtual functions if you have a virtual template class, all virtual functions will be generated for any parameter combinations.

Evan Dark
  • 1,311
  • 7
  • 7
  • 2
    Actually, any decent linker will merge functions that have different names but identical assembly instructions in non-debug builds. You can easily see this happen when you try to debug an optimized build. It's enabled via /OPT:ICF and /Gy in Visual Studio. – Adam Jul 28 '15 at 00:18
  • I would say the main outcome of C++ code bloat is slow build times, which is a problem for many C++ projects. The possible increase of resulting binary does not seem to be a big problem today. – stgatilov Mar 10 '20 at 06:24