GitLab now enforces expiry dates on tokens that originally had no set expiration date. Those tokens were given an expiration date of one year later. Please review your personal access tokens, project access tokens, and group access tokens to ensure you are aware of upcoming expirations. Administrators of GitLab can find more information on how to identify and mitigate interruption in our documentation.
{"metadata":{"orig_nbformat":4,"kernelspec":{"display_name":"C++14","language":"C++14","name":"xcpp14"},"language_info":{"codemirror_mode":"text/x-c++src","file_extension":".cpp","mimetype":"text/x-c++src","name":"c++","version":"14"}},"nbformat_minor":5,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Template Programming: Basics","metadata":{},"id":"741a2490"},{"cell_type":"markdown","source":"## Motivation\n\nIn our first notebook **01_Overloading** we started with implementing two free-functions that returned the magnitude of their argument:","metadata":{"tags":[]},"id":"a61d218d"},{"cell_type":"code","source":"// Version for int\nint getMagnitude( int input ) {\n return input > 0 ? input : -input;\n}","metadata":{"trusted":true},"execution_count":null,"outputs":[],"id":"d4a7139f"},{"cell_type":"code","source":"// Version for double\ndouble getMagnitude( double input ) {\n return input > 0.0 ? input : -input;\n}","metadata":{"trusted":true},"execution_count":null,"outputs":[],"id":"cfbe1b82"},{"cell_type":"markdown","source":"Comparison of the code shows that there are three differences between the two functions:\n1. type of argument\n1. type of return value\n1. type of literal used\n\nThe last one can be eliminated by performing a static cast.","metadata":{},"id":"6f937e9d"},{"cell_type":"code","source":"// Version for double\ndouble getMagnitude( double input ) {\n return input > static_cast< double >( 0 ) ? input : -input;\n}","metadata":{"trusted":true},"execution_count":null,"outputs":[],"id":"0225265d"},{"cell_type":"markdown","source":"Now imagine that we want to have one function for every signed integer data type and each floating point type in C++, i.e.\n- signed char\n- signed short\n- signed int\n- signed long\n- signed long long\n- float\n- double\n- long double\n\nThis implies that we need to implement eight different versions of `getMagnitude`, which, however, are always following the same structure:\n\n```c++\n// Basic pattern of our free-function for a datatype TYPE is:\nTYPE getMagnitude( TYPE input ) {\n return input > static_cast< TYPE >( 0 ) ? input : -input;\n}\n```","metadata":{},"id":"13e637a9"},{"cell_type":"markdown","source":"---\n**Alternatives?**\n\nIt would be nice, if we did not have to write the (basically) same code multiple times\n- Repetition is dull and error-prone\n- We need to maintain (basically) the same code piece multiple times -> more work and error-prone\n\nFortunately there are ways to avoid this. The two prominent ones applicable in our situation are:\n1. (Automatic) Code Generation\n1. Generic Programming","metadata":{},"id":"3013b562"},{"cell_type":"markdown","source":"### (Automatic) Code Generation\n\nHere the idea is to let the computer generate the source code that the compiler sees itself following our instructions.\n\nFor this we need some (external) code generator. Often this is written in some other language than the generated code itself (e.g. in Python).\n\n> An example of this would be the \n<a href=\"https://fenicsproject.org\">FEniCS</a> project, a popular open-source computing platform for solving partial differential equations with Finite Elements. You describe your PDE problem in Python and from this efficient C++ code is generated, compiled and executed (very rough description :-) \n\nOften such generators are tuned to a specific field of problems and involve a so called\nDSL (domain specific language) to describe what is to be solved/generated.\n\n> For more on this see e.g. the publications of the <a href=\"https://www.exastencils.fau.de\">ExaStencils</a> project.\n\nAutomatic code generation plays an increasingly important role in high-performance scientific applications for **performance tuning** and **(performance) portability** (think CPU vs. GPU vs FPGA vs ...)","metadata":{"tags":[]},"id":"6dc7ea86"},{"cell_type":"markdown","source":"### 'Inline' Code Generation\nIn C++ it is possible to do some (limited) code generation on-the-fly using the capabilities of the **preprocessor**. An interesting overview on that can be found e.g. in <a href=\"https://link.springer.com/book/10.1007/978-3-662-48550-7\">C++ Metaprogrammierung</a>, Lemke, 2016, Springer.\n\nWe are going to take a look at this as an example, before proceeding to templates.","metadata":{},"id":"3191c55f"},{"cell_type":"code","source":"%%file getMag.cpp\n\n// we use a parameterised macro that represents the pattern of our function\n#define GETMAG( TYPE ) \\\n TYPE getMagnitude( TYPE value ) { \\\n return value > static_cast< TYPE >( 0 ) ? value : -value; \\\n}\n\n// Now we can let the preprocessor generate the source code by using the\n// macro with the corresponding datatype we need\nGETMAG( int )\nGETMAG( double )\nGETMAG( float )","metadata":{"trusted":true},"execution_count":1,"outputs":[{"name":"stdout","text":"Overwriting getMag.cpp\n","output_type":"stream"}],"id":"988d30ea"},{"cell_type":"markdown","source":"Now let us check how the result of running the preprocessor on that source code looks like:","metadata":{},"id":"625b1b11"},{"cell_type":"code","source":"!cpp getMag.cpp","metadata":{"trusted":true},"execution_count":2,"outputs":[{"name":"stdout","text":"# 1 \"getMag.cpp\"\n# 1 \"<built-in>\"\n# 1 \"<command-line>\"\n# 1 \"/usr/include/stdc-predef.h\" 1 3 4\n# 1 \"<command-line>\" 2\n# 1 \"getMag.cpp\"\n# 10 \"getMag.cpp\"\nint getMagnitude( int value ) { return value > static_cast< int >( 0 ) ? value : -value; }\ndouble getMagnitude( double value ) { return value > static_cast< double >( 0 ) ? value : -value; }\nfloat getMagnitude( float value ) { return value > static_cast< float >( 0 ) ? value : -value; }\n","output_type":"stream"}],"id":"8baeee45"},{"cell_type":"markdown","source":"---\nPreprocessing is an integral part of compilation of a C++ program (think of the `#include` directive) so this integrates seamlessly:","metadata":{},"id":"9ea5d77e"},{"cell_type":"code","source":"%%file getMag.cpp\n\n// we use a parameterised macro that represents the pattern of our function\n#define GETMAG( TYPE ) \\\n TYPE getMagnitude( TYPE value ) { \\\n return value < static_cast< TYPE >( 0 ) ? -value : value; \\\n}\n\n// Now we can let the preprocessor generate the source code by using the\n// macro with the corresponding datatype we need\nGETMAG( signed char )\nGETMAG( short )\nGETMAG( int )\nGETMAG( long )\nGETMAG( float )\nGETMAG( double )\n \n#include <iostream>\nint main() {\n\n short s = -2;\n float x = 3.5f;\n double v = 12.34;\n\n std::cout << \"|\" << s << \"| = \" << getMagnitude( s ) << std::endl;\n std::cout << '|' << x << \"| = \" << getMagnitude( x ) << std::endl;\n std::cout << '|' << v << \"| = \" << getMagnitude( v ) << std::endl;\n}","metadata":{"trusted":true},"execution_count":3,"outputs":[{"name":"stdout","text":"Overwriting getMag.cpp\n","output_type":"stream"}],"id":"b1d7de95"},{"cell_type":"code","source":"!g++ -Wall -Wextra getMag.cpp","metadata":{"trusted":true},"execution_count":4,"outputs":[],"id":"b85f934b"},{"cell_type":"code","source":"!./a.out","metadata":{"trusted":true},"execution_count":5,"outputs":[{"name":"stdout","text":"|-2| = 2\n|3.5| = 3.5\n|12.34| = 12.34\n","output_type":"stream"}],"id":"00684f47"},{"cell_type":"markdown","source":"The downside of this approach is that the C/C++ preprocessor has nearly no understanding of the language itself. Hence, it cannot perform any syntax checking or the like.\n\nWriting longer functions will become irksome, also, due to the line continuation stuff. *(and no syntax high-lighting or indentation ... by editors).*\n\nAlso we will need to **explicitely have a line for each `getMagnitude()` version** that might be used. Code will not be generated on a need-to-have basis.","metadata":{},"id":"6631c752"},{"cell_type":"markdown","source":"### Generic Programming\nThe idea here is to not use an external code generator, but instead provide functionality in the programming language itself that allows to accomplish what we want.\n\nFrom <a href=\"https://en.wikipedia.org/wiki/Generic_programming\">Wikipedia</a>:\n> Generic programming is a style of computer programming in which algorithms are written in terms of types to-be-specified-later that are then instantiated when needed for specific types provided as parameters. \n\nIn C++ the approach to support generic programming is to use **templates**.","metadata":{},"id":"dda3bd44"},{"cell_type":"markdown","source":"---\nSo how would we takle our problem with templates?\n\nInstead of multiple free-functions we implement a **single templated version** of it:","metadata":{},"id":"c9b5ee37"},{"cell_type":"code","source":"template< typename T >\nT getMagnitude( T value ) {\n return value > static_cast< T >( 0 ) ? value : -value;\n}","metadata":{"trusted":true},"execution_count":null,"outputs":[],"id":"90ddfa90"},{"cell_type":"markdown","source":"When the compiler recognises that an instance of the templated function is needed for a specific data-type it will instantiate it (i.e. it will compile machine-code for this version): ","metadata":{},"id":"e2df86d3"},{"cell_type":"code","source":"#include <iostream>\nshort s = -5;\nstd::cout << \"|\" << s << \"| = \" << getMagnitude( s );","metadata":{"trusted":true},"execution_count":null,"outputs":[],"id":"f5be2836"},{"cell_type":"markdown","source":"---\nA closer look at the **function template**:\n\n```c++\ntemplate< typename T >\nT getMagnitude( T value ) {\n return value < static_cast< T >( 0 ) ? -value : value;\n}\n```\n\n* `template< typename T >`\n - informs the compiler that it is a templated function\n - in the example there is a single **template parameter** (often denoted as `T`, but that is\n just convention)\n - `typename` specifies `T` to be a **type** template parameter (`class` can be used interchangeably)\n - instead of a datatype a parameter can also be a basic datatype ( e.g. `template <int n>` ), or a *template template parameter*\n* In the body of the template declaration `T` is a typedef-name that aliases the type supplied when the template is instantiated","metadata":{},"id":"740ee0bd"},{"cell_type":"markdown","source":"---\nNow let's take a closer look at the **instantiation**:","metadata":{},"id":"d6754844-ef2d-496e-adab-1367a463c19f"},{"cell_type":"code","source":"%%file withTemplates.cpp\n\ntemplate< typename T >\nT getMagnitude( T value ) {\n return value > static_cast< T >( 0 ) ? value : -value;\n}\n \nint main() {\n\n short s = -2;\n float x = 3.5f;\n double v = 12.34;\n\n getMagnitude( s );\n getMagnitude( x );\n getMagnitude( v );\n getMagnitude( -10L );\n}","metadata":{"trusted":true},"execution_count":null,"outputs":[],"id":"8f2ab60c"},{"cell_type":"code","source":"!g++ -save-temps -c withTemplates.cpp","metadata":{"trusted":true},"execution_count":null,"outputs":[],"id":"96551727-c1b0-4b97-9bff-11e9eeac731e"},{"cell_type":"code","source":"!nm -C withTemplates.o","metadata":{"trusted":true},"execution_count":null,"outputs":[],"id":"d3e0f1fc-f85a-4adc-a63f-ba7fdea02a2d"},{"cell_type":"markdown","source":"We observe that the object file contains instantiations of all four versions that are required in our source code, *but not more*. This is called **implicit instantiation**.\n\nA look at the file after preprocessing (`-save-temps` option) shows that no extra source code got generated. It really is something the compiler handles for us.","metadata":{},"id":"d63382c0-e766-422b-ba97-7824de507c3a"},{"cell_type":"code","source":"!cat withTemplates.ii","metadata":{"trusted":true},"execution_count":null,"outputs":[],"id":"9c620720-b4cc-46a0-bde0-57452bcd3a0b"},{"cell_type":"code","source":"%%file withTemplates.cpp\n\ntemplate< typename T >\nT getMagnitude( T value ) {\n return value > static_cast< T >( 0 ) ? value : -value;\n}\n\n// explicit instantiation\ntemplate float getMagnitude( float );\n\nint main() {\n\n // implicit instantiation\n getMagnitude( -2 );\n}","metadata":{"trusted":true},"execution_count":null,"outputs":[],"id":"38aa85e7-83d9-4ae0-ac05-80cf187ee9f3"},{"cell_type":"code","source":"!g++ -save-temps -c withTemplates.cpp","metadata":{"trusted":true},"execution_count":null,"outputs":[],"id":"76bfe507-bc01-457a-aeb5-38e2db572cac"},{"cell_type":"code","source":"!nm -C withTemplates.o","metadata":{"trusted":true},"execution_count":null,"outputs":[],"id":"e707d5e2-6d8d-4ee9-9046-b749d154146b"},{"cell_type":"markdown","source":"When might explicit instantiation be required?\n\nLet us modify our example to have the usual structure of *header file* (.hpp) and *source code file* (.cpp) and a separate *driver file*:","metadata":{},"id":"76ecc704-ac09-4343-b561-7817373aa1c9"},{"cell_type":"code","source":"%%file withTemplates.cpp\n\ntemplate< typename T >\nT getMagnitude( T value ) {\n return value > static_cast< T >( 0 ) ? value : -value;\n}","metadata":{"trusted":true},"execution_count":null,"outputs":[],"id":"a854c3ce-1865-4ec1-b092-87be2a50d13f"},{"cell_type":"code","source":"%%file withTemplates.hpp\n\ntemplate< typename T > T getMagnitude( T value );","metadata":{"trusted":true},"execution_count":null,"outputs":[],"id":"b3b433db-8509-43fb-9946-579ffd4c5dfb"},{"cell_type":"code","source":"%%file driver.cpp\n\n#include \"withTemplates.hpp\"\nint main() {\n getMagnitude( -1.2345f );\n}","metadata":{"trusted":true},"execution_count":null,"outputs":[],"id":"c96bbc17-3771-453b-9544-eae96dd936f0"},{"cell_type":"code","source":"!g++ driver.cpp","metadata":{"trusted":true},"execution_count":null,"outputs":[],"id":"0cea5aa2-240b-493c-8afc-c560b0dff82c"},{"cell_type":"markdown","source":"Okay, that is not different from the usual. Let us also compile the source code file:","metadata":{},"id":"976e6ef4-ce58-4a4f-acf9-bff9d122923d"},{"cell_type":"code","source":"!g++ driver.cpp withTemplates.cpp","metadata":{"trusted":true},"execution_count":null,"outputs":[],"id":"e98425fb-dc85-4e89-9f9b-dc310b1c65bb"},{"cell_type":"markdown","source":"Still a problem! Why's that?","metadata":{},"id":"0ace12fa-d5a8-48ab-8d9b-250c71847812"},{"cell_type":"markdown","source":"\n\n\n*intentionally left blank ;-)*\n\n\n","metadata":{},"id":"bf20a5c9-5d48-405f-861e-afc7d699ff41"},{"cell_type":"markdown","source":"When we compile the driver the compiler will recognise that it need a version of `getMagnitude()` for `float`:","metadata":{},"id":"1517f452-ef0e-471a-82c0-880e829a51ff"},{"cell_type":"code","source":"!g++ -c driver.cpp","metadata":{"trusted":true},"execution_count":null,"outputs":[],"id":"846d3074-53c4-4dfe-94af-43b82f49d0a8"},{"cell_type":"code","source":"!nm -C driver.o","metadata":{"trusted":true},"execution_count":null,"outputs":[],"id":"7f84b616-97d9-4ce0-a588-7bed26c4b4aa"},{"cell_type":"markdown","source":"However, it cannot instantiate it, because it does not see the definition of the template function, but only its prototype!\n\n- That is no error.\n- Finding an instance is then delegated to the linker.\n\nOkay. So now let us compile the source code file and check the contents of the resulting object file:","metadata":{},"id":"43c992a6-7dca-4aab-8293-328b0cd8bf76"},{"cell_type":"code","source":"!g++ -c withTemplates.cpp","metadata":{"trusted":true},"execution_count":null,"outputs":[],"id":"15c7f98e-33fd-4bca-8293-5a19352c43ac"},{"cell_type":"code","source":"!nm -C withTemplates.o","metadata":{"trusted":true},"execution_count":null,"outputs":[],"id":"5f6a4521-affc-4147-a33a-a7fd4f6051ce"},{"cell_type":"markdown","source":"Oops. Nothing. Why?\n\nBecause in the source code file no template instance is required and the template function itself cannot be compiled with out an argument for the datatype!","metadata":{},"id":"b955ee26-e340-44e5-a264-66beda062321"},{"cell_type":"markdown","source":"---\nSplitting declaration and definition of a template function requires us to use explicit instantiation.","metadata":{},"id":"6bd45ab9-c3b9-4ec2-b093-1a2f327a0526"},{"cell_type":"code","source":"%%file withTemplates.cpp\n\ntemplate< typename T >\nT getMagnitude( T value ) {\n return value > static_cast< T >( 0 ) ? value : -value;\n}\n\ntemplate float getMagnitude( float );","metadata":{"trusted":true},"execution_count":null,"outputs":[],"id":"e0aa1181-d4b2-4fc1-95fe-ead0f86b2d5b"},{"cell_type":"code","source":"!g++ -save-temps driver.cpp withTemplates.cpp","metadata":{"trusted":true},"execution_count":null,"outputs":[],"id":"e86d0de4-3e7e-48d1-8b2f-3a2b29e44842"},{"cell_type":"code","source":"!nm -C withTemplates.o","metadata":{"trusted":true},"execution_count":null,"outputs":[],"id":"380b4117-4a81-45dc-a578-88f233d8726e"},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[],"id":"68c3df86-8d83-4b24-bb13-8bb90e170eb2"}]}
\ No newline at end of file
%% Cell type:markdown id:741a2490 tags:
# Template Programming: Basics
%% Cell type:markdown id:a61d218d tags:
## Motivation
In our first notebook **01_Overloading** we started with implementing two free-functions that returned the magnitude of their argument:
%% Cell type:code id:d4a7139f tags:
``` C++14
// Version for int
int getMagnitude( int input ) {
return input > 0 ? input : -input;
}
```
%% Cell type:code id:cfbe1b82 tags:
``` C++14
// Version for double
double getMagnitude( double input ) {
return input > 0.0 ? input : -input;
}
```
%% Cell type:markdown id:6f937e9d tags:
Comparison of the code shows that there are three differences between the two functions:
1. type of argument
1. type of return value
1. type of literal used
The last one can be eliminated by performing a static cast.
Now imagine that we want to have one function for every signed integer data type and each floating point type in C++, i.e.
- signed char
- signed short
- signed int
- signed long
- signed long long
- float
- double
- long double
This implies that we need to implement eight different versions of `getMagnitude`, which, however, are always following the same structure:
```c++
// Basic pattern of our free-function for a datatype TYPE is:
TYPEgetMagnitude(TYPEinput){
returninput>static_cast<TYPE>(0)?input:-input;
}
```
%% Cell type:markdown id:3013b562 tags:
---
**Alternatives?**
It would be nice, if we did not have to write the (basically) same code multiple times
- Repetition is dull and error-prone
- We need to maintain (basically) the same code piece multiple times -> more work and error-prone
Fortunately there are ways to avoid this. The two prominent ones applicable in our situation are:
1. (Automatic) Code Generation
1. Generic Programming
%% Cell type:markdown id:6dc7ea86 tags:
### (Automatic) Code Generation
Here the idea is to let the computer generate the source code that the compiler sees itself following our instructions.
For this we need some (external) code generator. Often this is written in some other language than the generated code itself (e.g. in Python).
> An example of this would be the
<ahref="https://fenicsproject.org">FEniCS</a> project, a popular open-source computing platform for solving partial differential equations with Finite Elements. You describe your PDE problem in Python and from this efficient C++ code is generated, compiled and executed (very rough description :-)
Often such generators are tuned to a specific field of problems and involve a so called
DSL (domain specific language) to describe what is to be solved/generated.
> For more on this see e.g. the publications of the <a href="https://www.exastencils.fau.de">ExaStencils</a> project.
Automatic code generation plays an increasingly important role in high-performance scientific applications for **performance tuning** and **(performance) portability** (think CPU vs. GPU vs FPGA vs ...)
%% Cell type:markdown id:3191c55f tags:
### 'Inline' Code Generation
In C++ it is possible to do some (limited) code generation on-the-fly using the capabilities of the **preprocessor**. An interesting overview on that can be found e.g. in <ahref="https://link.springer.com/book/10.1007/978-3-662-48550-7">C++ Metaprogrammierung</a>, Lemke, 2016, Springer.
We are going to take a look at this as an example, before proceeding to templates.
%% Cell type:code id:988d30ea tags:
``` C++14
%%file getMag.cpp
// we use a parameterised macro that represents the pattern of our function
#define GETMAG( TYPE ) \
TYPE getMagnitude( TYPE value ) { \
return value > static_cast< TYPE >( 0 ) ? value : -value; \
}
// Now we can let the preprocessor generate the source code by using the
// macro with the corresponding datatype we need
GETMAG( int )
GETMAG( double )
GETMAG( float )
```
%% Output
Overwriting getMag.cpp
%% Cell type:markdown id:625b1b11 tags:
Now let us check how the result of running the preprocessor on that source code looks like:
%% Cell type:code id:8baeee45 tags:
``` C++14
!cpp getMag.cpp
```
%% Output
# 1 "getMag.cpp"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "getMag.cpp"
# 10 "getMag.cpp"
int getMagnitude( int value ) { return value > static_cast<int>( 0 ) ? value : -value; }
double getMagnitude( double value ) { return value > static_cast<double>( 0 ) ? value : -value; }
float getMagnitude( float value ) { return value > static_cast<float>( 0 ) ? value : -value; }
%% Cell type:markdown id:9ea5d77e tags:
---
Preprocessing is an integral part of compilation of a C++ program (think of the `#include` directive) so this integrates seamlessly:
%% Cell type:code id:b1d7de95 tags:
``` C++14
%%file getMag.cpp
// we use a parameterised macro that represents the pattern of our function
#define GETMAG( TYPE ) \
TYPE getMagnitude( TYPE value ) { \
return value < static_cast< TYPE >( 0 ) ? -value : value; \
}
// Now we can let the preprocessor generate the source code by using the
// macro with the corresponding datatype we need
GETMAG( signed char )
GETMAG( short )
GETMAG( int )
GETMAG( long )
GETMAG( float )
GETMAG( double )
#include <iostream>
int main() {
short s = -2;
float x = 3.5f;
double v = 12.34;
std::cout << "|" << s << "| = " << getMagnitude( s ) << std::endl;
std::cout << '|' << x << "| = " << getMagnitude( x ) << std::endl;
std::cout << '|' << v << "| = " << getMagnitude( v ) << std::endl;
}
```
%% Output
Overwriting getMag.cpp
%% Cell type:code id:b85f934b tags:
``` C++14
!g++ -Wall -Wextra getMag.cpp
```
%% Cell type:code id:00684f47 tags:
``` C++14
!./a.out
```
%% Output
|-2| = 2
|3.5| = 3.5
|12.34| = 12.34
%% Cell type:markdown id:6631c752 tags:
The downside of this approach is that the C/C++ preprocessor has nearly no understanding of the language itself. Hence, it cannot perform any syntax checking or the like.
Writing longer functions will become irksome, also, due to the line continuation stuff. *(and no syntax high-lighting or indentation ... by editors).*
Also we will need to **explicitely have a line for each `getMagnitude()` version** that might be used. Code will not be generated on a need-to-have basis.
%% Cell type:markdown id:dda3bd44 tags:
### Generic Programming
The idea here is to not use an external code generator, but instead provide functionality in the programming language itself that allows to accomplish what we want.
From <ahref="https://en.wikipedia.org/wiki/Generic_programming">Wikipedia</a>:
> Generic programming is a style of computer programming in which algorithms are written in terms of types to-be-specified-later that are then instantiated when needed for specific types provided as parameters.
In C++ the approach to support generic programming is to use **templates**.
%% Cell type:markdown id:c9b5ee37 tags:
---
So how would we takle our problem with templates?
Instead of multiple free-functions we implement a **single templated version** of it:
%% Cell type:code id:90ddfa90 tags:
``` C++14
template< typename T >
T getMagnitude( T value ) {
return value > static_cast< T >( 0 ) ? value : -value;
}
```
%% Cell type:markdown id:e2df86d3 tags:
When the compiler recognises that an instance of the templated function is needed for a specific data-type it will instantiate it (i.e. it will compile machine-code for this version):
%% Cell type:code id:f5be2836 tags:
``` C++14
#include <iostream>
short s = -5;
std::cout << "|" << s << "| = " << getMagnitude( s );
```
%% Cell type:markdown id:740ee0bd tags:
---
A closer look at the **function template**:
```c++
template<typenameT>
TgetMagnitude(Tvalue){
returnvalue<static_cast<T>(0)?-value:value;
}
```
*`template< typename T >`
- informs the compiler that it is a templated function
- in the example there is a single **template parameter** (often denoted as `T`, but that is
just convention)
-`typename` specifies `T` to be a **type** template parameter (`class` can be used interchangeably)
- instead of a datatype a parameter can also be a basic datatype ( e.g. `template <int n>` ), or a *template template parameter*
* In the body of the template declaration `T` is a typedef-name that aliases the type supplied when the template is instantiated
We observe that the object file contains instantiations of all four versions that are required in our source code, *but not more*. This is called **implicit instantiation**.
A look at the file after preprocessing (`-save-temps` option) shows that no extra source code got generated. It really is something the compiler handles for us.
Because in the source code file no template instance is required and the template function itself cannot be compiled with out an argument for the datatype!