compilation control and code bloat in templates - c++

I am reading about templates in apllied C++ book and it is mentioned as below
Templates create code bloat. The compiler will instantiate a template
object for each pixel type. Even if your users only need limited
types, the image processing routines may need additional types for
temporary images and the like.
Not having to be templated object has the advantage of giving us
control of how the object will be compiled, and lets us control code
bloat.
My questions on above text
What does author mean by "Even if your users only need limited types, the image processing routines may need additional types for temporary images and the like." ?
What does author mean by "Not having to be templated object has the advantage of giving us control of how the object will be compiled" ?
Request your help in understanding above statements. It would be good if explained with simple examples.
Thanks for your time and help.

The author is right that templates may create so-called code-bloat, but his explanations are fuzzy...
Let us a start with a primer on code-bloat.
There is an annoying interaction in the C++ Standard between templates and function pointers:
Each instantiation of a template with a given set of parameters is its own types
Two different functions should have different addresses
Since two different instantiations (one with int and one with long for example) are different types, the functions associated with them are different functions, and thus they need different addresses.
An optimizing compiler is allowed to actually merge functions under the as-if rule: if the programmer cannot realize they were merged. The naive attempt is to try and prove that the address of one of them is never taken, this is futile. A more clever strategy is to merge the function bodies, but still provide a different address:
; assembly-like code
function_instantiation_1:
nop ; offset to have different addresses
function_instantiation_2:
; body of both functions
However a practical problem is to identify such functions that could be merged, given the sheer number of functions there are.
So ? If one wishes to limit the amount of code produced, one just has to limit the number of instantiations. I find the author claim that the image processing routines may need additional types for temporary images and the like dubious. The set of types within a program is generally fairly restricted, and there are not gazillions of image types.

Related

How does the compiler define the classes in type_traits?

In C++11 and later, the <type_traits> header contains many classes for type checking, such as std::is_empty, std::is_polymorphic, std::is_trivially_constructible and many others.
While we use these classes just like normal classes, I cannot figure out any way to possibly write the definition of these classes. No amount of SFINAE (even with C++14/17 rules) or other method seems to be able to tell if a class is polymorphic, empty, or satisfy other properties. An class that is empty still occupies a positive amount of space as the class must have a unique address.
How then, might compilers define such classes in C++? Or perhaps it is necessary for the compiler to be intrinsically aware of these class names and parse them specially?
Back in the olden days, when people were first fooling around with type traits, they wrote some really nasty template code in attempts to write portable code to detect certain properties. My take on this was that you had to put a drip-pan under your computer to catch the molten metal as the compiler overheated trying to compile this stuff. Steve Adamczyk, of Edison Design Group (provider of industrial-strength compiler frontends), had a more constructive take on the problem: instead of writing all this template code that takes enormous amounts of compiler time and often breaks them, ask me to provide a helper function.
When type traits were first formally introduced (in TR1, 2006), there were several traits that nobody knew how to implement portably. Since TR1 was supposed to be exclusively library additions, these couldn't count on compiler help, so their specifications allowed them to get an answer that was occasionally wrong, but they could be implemented in portable code.
Nowadays, those allowances have been removed; the library has to get the right answer. The compiler help for doing this isn't special knowledge of particular templates; it's a function call that tells you whether a particular class has a particular property. The compiler can recognize the name of the function, and provide an appropriate answer. This provides a lower-level toolkit that the traits templates can use, individually or in combination, to decide whether the class has the trait in question.

2nd phase compilation in templates

I am trying to understand the compilation process and the code generation process in c++ template universe.
I have read that during the first phase of compilation only the basic syntax is checked(in templated code).
And that the actual code is generated only for those data types which are used for which the compilation is done completely- this is termed as second phase compilation.
I am not able to understand that how can a compiler know for which data type can the templated code be called and for which to generate the code(and hence do 2nd phase compilation). There might be cases when the function calls(in case off function templates) might not be so strightforward to derive the datatype during compile time, these can be derived only during runtime basedon input from user.
Assuming i have a written a huge code using templates with a lot of conditions based on which it generates new instance of templated code(lets say new instance of datatype for a class). I cant test the code for all the data types. So does it mean that if i test it for a couple of data types, there are still chances of my code failing unexpectedly for some other data types? If so, how can i ensure to force 2nd compilation for all the data types(irrespective of that data type based on my input is instantiated or not).
The types determined during compilation time only rely on the static information. A function template that is used with a particular type will generate code for that type, since the option needs to be available in the runtime. If it can be statically determined that a function call will never happen, though, I think that the compiler might omit that implementation, but there are certain cases that'd still force that.
You can't test for all datatypes, since that's an infinite set. You can create a set of all standard types, but you obviously can't check every user-defined type ever. The idea in generic code is to not depend on the particulars of the type you're allowing to pass it. Alternatively, you might close the set of possible instances to only include the types you sanction.
I am not able to understand that how can a compiler know for which data type can the templated code be called
The compiler knows for which data types the templated code is actually called because it sees every place in the program where the templated code is actually called. No magic here. Instantiation happens at call sites. No instantiation is done for types that are not used in actual existing calls.
there are still chances of my code failing
This is true for all test-based validation, templates or no templates, and even for things other than software. You cannot cover all possible use cases by tests. It's a fundamental fact of life. Deal with it... somehow.

C++ Templates: Are template ínstantiations inlined? Are there drawbacks in performance?

When some C++ entity, such as a structure, class, or function, is declared as a template, then the definitions provided for said entities are solely blue-prints which must be instantiated.
Due to the fact that a template entity must be defined when it is declared (which is commonly header files) I have the conception, which I try to convince myself as wrong, that when after a template has been instantiated it will be inlined by the compiler. I would like to ask if this is so?
The answer for this question raises my suspicion when I read the the paragraph:
"Templates can lead to slower compile-times and possibly larger
executable, especially with older compilers."
Slower compile-times are clear as template must be instantiated but why "possibly larger executables"? In what ways should this be interpreted? Should I interpret this as 'many functions are inlined' or 'the executable's size increases if there are many template instantiations, that is the same template is instantiated with a lot of different types, which causes several copies of the same entity to be there'?
In the latter case, does a larger executable size cause the software to run more slowly seeing that more code must be loaded into memory which will in turn cause expensive paging?
Also, as these questions are also somewhat compiler dependent I am interested in the Visual C++ compiler. Generalised answers concerning what most compilers do give a good insight as well.
Thank you in advance.
Due to the fact that a template entity must be defined when it is declared (which is commonly header files)
Not true. You can declare and define template classes, methods and functions separately, just like you can other classes, methods and functions.
I have the conception, which I try to convince myself as wrong, that when after a template has been instantiated it will be inlined by the compiler. I would like to ask if this is so?
Some of it may be, or all of it, or none of it. The compiler will do what it deems is best.
Slower compile-times are clear as template must be instantiated but why "possibly larger executables"? In what ways should this be interpreted?
It could be interpreted a number of ways. In the same way that a bottle of Asprin contains the warning "may induce <insert side-effects here>".
Should I interpret this as 'many functions are inlined' or 'the executable's size increases if there are many template instantiations, that is the same template is instantiated with a lot of different types, which causes several copies of the same entity to be there'?
You won't have several copies of the same entity - the compiler suite is obliged to see to that. Even if methods are inline, the address of the method will:
always exist, and
be the same address when referenced by multiple compilation units.
What you may find is that you start creating more types than you intended. For example std::vector<int> is a completely different type to std::vector<double>. foo<X>() is a different function to foo<Y>(). The number of types and function definitions in your program can grow quickly.
In the latter case, does a larger executable size cause the software to run more slowly seeing that more code must be loaded into memory which will in turn cause expensive paging?
Excessive paging, probably not. Excessive cache misses, quite possibly. Often, optimising for smaller code is a good strategy for achieving good performance (under certain circumstances such as when there is little data being accessed and it's all in-cache).
Whether they are inlined is always up to the compiler. Non-inlined template instantiations are shared for all similar instantiations.
So a lot of translation units all wanting to make a Foo<int> will share the Foo instantiation. Obviously if Foo<int> is a function, and the compiler decides in each case to inline it then the code is repeated. However the choice to inline is because the optimization of doing so seems highly likely to be superior to a function call.
Technically there could be a corner case where a template causes slower execution. I work on software which has super tight inner loops for which we do a lot of performance measurements. We use a number of template functions and classes and it has yet to show up a degradation compared to writing the code by hand.
I can't be certain but I think you'd have to have a situation where the template:
- generated non-inlined code
- did so for multiple instantiations
- could have been one hand-written function
- hand-written function incurs no run-time penalty for being one function (ie: no implicit conversions involving runtime checks)
Then it's possible that you have a case where the single-handwritten-function fits within the CPU's instruction cache but the multiple template instantiations do not.

Will C++ compiler generate code for each template type?

I have two questions about templates in C++. Let's imagine I have written a simple List and now I want to use it in my program to store pointers to different object types (A*, B* ... ALot*). My colleague says that for each type there will be generated a dedicated piece of code, even though all pointers in fact have the same size.
If this is true, can somebody explain me why? For example in Java generics have the same purpose as templates for pointers in C++. Generics are only used for pre-compile type checking and are stripped down before compilation. And of course the same byte code is used for everything.
Second question is, will dedicated code be also generated for char and short (considering that they both have the same size and there are no specialization).
If this makes any difference, we are talking about embedded applications.
I have found a similar question, but it did not completely answer my question: Do C++ template classes duplicate code for each pointer type used?
Thanks a lot!
I have two questions about templates in C++. Let's imagine I have written a simple List and now I want to use it in my program to store pointers to different object types (A*, B* ... ALot*). My colleague says that for each type there will be generated a dedicated piece of code, even though all pointers in fact have the same size.
Yes, this is equivalent to having both functions written.
Some linkers will detect the identical functions, and eliminate them. Some libraries are aware that their linker doesn't have this feature, and factor out common code into a single implementation, leaving only a casting wrapper around the common code. Ie, a std::vector<T*> specialization may forward all work to a std::vector<void*> then do casting on the way out.
Now, comdat folding is delicate: it is relatively easy to make functions you think are identical, but end up not being the same, so two functions are generated. As a toy example, you could go off and print the typename via typeid(x).name(). Now each version of the function is distinct, and they cannot be eliminated.
In some cases, you might do something like this thinking that it is a run time property that differs, and hence identical code will be created, and the identical functions eliminated -- but a smart C++ compiler might figure out what you did, use the as-if rule and turn it into a compile-time check, and block not-really-identical functions from being treated as identical.
If this is true, can somebody explain me why? For example in Java generics have the same purpose as templates for pointers in C++. Generics are only used for per-compile type checking and are stripped down before compilation. And of course the same byte code is used for everything.
No, they aren't. Generics are roughly equivalent to the C++ technique of type erasure, such as what std::function<void()> does to store any callable object. In C++, type erasure is often done via templates, but not all uses of templates are type erasure!
The things that C++ does with templates that are not in essence type erasure are generally impossible to do with Java generics.
In C++, you can create a type erased container of pointers using templates, but std::vector doesn't do that -- it creates an actual container of pointers. The advantage to this is that all type checking on the std::vector is done at compile time, so there doesn't have to be any run time checks: a safe type-erased std::vector may require run time type checking and the associated overhead involved.
Second question is, will dedicated code be also generated for char and short (considering that they both have the same size and there are no specialization).
They are distinct types. I can write code that will behave differently with a char or short value. As an example:
std::cout << x << "\n";
with x being a short, this print an integer whose value is x -- with x being a char, this prints the character corresponding to x.
Now, almost all template code exists in header files, and is implicitly inline. While inline doesn't mean what most folk think it means, it does mean that the compiler can hoist the code into the calling context easily.
If this makes any difference, we are talking about embedded applications.
What really makes a difference is what your particular compiler and linker is, and what settings and flags they have active.
The answer is maybe. In general, each instantiation of a
template is a unique type, with a unique implementation, and
will result in a totally independent instance of the code.
Merging the instances is possible, but would be considered
"optimization" (under the "as if" rule), and this optimization
isn't wide spread.
With regards to comparisons with Java, there are several points
to keep in mind:
C++ uses value semantics by default. An std::vector, for
example, will actually insert copies. And whether you're
copying a short or a double does make a difference in the
generated code. In Java, short and double will be boxed,
and the generated code will clone a boxed instance in some way;
cloning doesn't require different code, since it calls a virtual
function of Object, but physically copying does.
C++ is far more powerful than Java. In particular, it allows
comparing things like the address of functions, and it requires
that the functions in different instantiations of templates have
different addresses. Usually, this is not an important point,
and I can easily imagine a compiler with an option which tells
it to ignore this point, and to merge instances which are
identical at the binary level. (I think VC++ has something like
this.)
Another issue is that the implementation of a template in C++
must be present in the header file. In Java, of course,
everything must be present, always, so this issue affects all
classes, not just template. This is, of course, one of the
reasons why Java is not appropriate for large applications. But
it means that you don't want any complicated functionality in a
template; doing so loses one of the major advantages of C++,
compared to Java (and many other languages). In fact, it's not
rare, when implementing complicated functionality in templates,
to have the template inherit from a non-template class which
does most of the implementation in terms of void*. While
implementing large blocks of code in terms of void* is never
fun, it does have the advantage of offering the best of both
worlds to the client: the implementation is hidden in compiled
files, invisible in any way, shape or manner to the client.

Memory management for types in complex languages

I've come across a slight problem for writing memory management with regard to the internal representation of types in a compiler for statically typed, complex languages. Consider a simple snippet in C++ which easily demonstrates a type that refers to itself.
class X {
void f(const X&) {}
};
Types can have nearly infinitely complex relationships to each other. So, as a compiler process, how do you make sure that they are properly collected?
So far, I've decided that garbage collection might be the right way to go, which I wouldn't be too happy with because I want to write the compiler in C++, or alternatively, just leave them and never collect them for the life of the compile phase for which they are needed (which has a very fixed lifetime) and then collect them all afterwards. The problem with that is that if you had a lot of complex types, you could lose a lot of memory that way.
Memory management is easy, just have some table type-name -> type-descriptor for each declaration scopes. Types are uniquely identified by name, no matter how complex the nesting is. Even a recursive type is still only a single type. As tp1 says correctly, you typically perform multiple passes to fill in all blanks. For instance, you might check that a type name is known in the first pass and then compute all links, later on, you compute the type.
Keep in mind that languages like C don't have a really complex type system -- even though they have pointers (which allow for recursive types), there is not much type computation going on.
I think you can remove the cycles from the dependency graph by using separate objects to represent declarations and definitions. Assuming a type system similar to C++, you will then have a hierarchical dependency:
Function definitions depend on type definitions and function declarations
Type definitions depend on function and type declarations (and definitions of contained types)
Function declarations depend on type declarations
In your example, the dependency graph is f_def -> X_def -> f_decl -> X_decl.
With no cycles in the graph, you can manage objects using simple reference counting.