From 2ef01a86e1fc6c782a0af8e4802a0e0df81e845a Mon Sep 17 00:00:00 2001 From: Marcus Mohr <marcus.mohr@lmu.de> Date: Tue, 18 Jan 2022 15:07:24 +0100 Subject: [PATCH] Extends notebook #11: Template Basics --- images/cppInsights01.png | Bin 0 -> 59783 bytes notebooks/11_Template_Basics.ipynb | 1154 +++++++++++++++++++++++++++- 2 files changed, 1153 insertions(+), 1 deletion(-) create mode 100644 images/cppInsights01.png diff --git a/images/cppInsights01.png b/images/cppInsights01.png new file mode 100644 index 0000000000000000000000000000000000000000..a954b0694b144de8305eea04541d29ecf9f1eaf1 GIT binary patch literal 59783 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	UTTDjybPgmU||5ykvaT=r5t(l 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 literal 0 HcmV?d00001 diff --git a/notebooks/11_Template_Basics.ipynb b/notebooks/11_Template_Basics.ipynb index 1f9af8b..95d53c8 100644 --- a/notebooks/11_Template_Basics.ipynb +++ b/notebooks/11_Template_Basics.ipynb @@ -1 +1,1153 @@ -{"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 +{ + "cells": [ + { + "cell_type": "markdown", + "id": "741a2490", + "metadata": {}, + "source": [ + "# Template Programming: Basics" + ] + }, + { + "cell_type": "markdown", + "id": "a61d218d", + "metadata": { + "tags": [] + }, + "source": [ + "## Motivation\n", + "\n", + "In our first notebook **01_Overloading** we started with implementing two free-functions that returned the magnitude of their argument:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "d4a7139f", + "metadata": {}, + "outputs": [], + "source": [ + "// Version for int\n", + "int getMagnitude( int input ) {\n", + " return input > 0 ? input : -input;\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "cfbe1b82", + "metadata": {}, + "outputs": [], + "source": [ + "// Version for double\n", + "double getMagnitude( double input ) {\n", + " return input > 0.0 ? input : -input;\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "6f937e9d", + "metadata": {}, + "source": [ + "Comparison of the code shows that there are three differences between the two functions:\n", + "1. type of argument\n", + "1. type of return value\n", + "1. type of literal used\n", + "\n", + "The last one can be eliminated by performing a static cast." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "0225265d", + "metadata": {}, + "outputs": [], + "source": [ + "// Version for double\n", + "double getMagnitude( double input ) {\n", + " return input > static_cast< double >( 0 ) ? input : -input;\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "13e637a9", + "metadata": {}, + "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", + "\n", + "This 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:\n", + "TYPE getMagnitude( TYPE input ) {\n", + " return input > static_cast< TYPE >( 0 ) ? input : -input;\n", + "}\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "3013b562", + "metadata": {}, + "source": [ + "---\n", + "**Alternatives?**\n", + "\n", + "It 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", + "\n", + "Fortunately there are ways to avoid this. The two prominent ones applicable in our situation are:\n", + "1. (Automatic) Code Generation\n", + "1. Generic Programming" + ] + }, + { + "cell_type": "markdown", + "id": "6dc7ea86", + "metadata": { + "tags": [] + }, + "source": [ + "### (Automatic) Code Generation\n", + "\n", + "Here the idea is to let the computer generate the source code that the compiler sees itself following our instructions.\n", + "\n", + "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).\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", + "\n", + "Often such generators are tuned to a specific field of problems and involve a so called\n", + "DSL (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", + "\n", + "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", + "metadata": {}, + "source": [ + "### 'Inline' Code Generation\n", + "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 <a href=\"https://link.springer.com/book/10.1007/978-3-662-48550-7\">C++ Metaprogrammierung</a>, Lemke, 2016, Springer.\n", + "\n", + "We are going to take a look at this as an example, before proceeding to templates." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "988d30ea", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Writing getMag.cpp\n" + ] + } + ], + "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\n", + "GETMAG( int )\n", + "GETMAG( double )\n", + "GETMAG( float )" + ] + }, + { + "cell_type": "markdown", + "id": "625b1b11", + "metadata": {}, + "source": [ + "Now let us check how the result of running the preprocessor on that source code looks like:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "8baeee45", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "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\"\n", + "int getMagnitude( int value ) { return value > static_cast< int >( 0 ) ? value : -value; }\n", + "double getMagnitude( double value ) { return value > static_cast< double >( 0 ) ? value : -value; }\n", + "float getMagnitude( float value ) { return value > static_cast< float >( 0 ) ? value : -value; }\n" + ] + } + ], + "source": [ + "!cpp getMag.cpp" + ] + }, + { + "cell_type": "markdown", + "id": "9ea5d77e", + "metadata": {}, + "source": [ + "---\n", + "Preprocessing is an integral part of compilation of a C++ program (think of the `#include` directive) so this integrates seamlessly:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "b1d7de95", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting getMag.cpp\n" + ] + } + ], + "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\n", + "GETMAG( signed char )\n", + "GETMAG( short )\n", + "GETMAG( int )\n", + "GETMAG( long )\n", + "GETMAG( float )\n", + "GETMAG( double )\n", + " \n", + "#include <iostream>\n", + "int 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", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "b85f934b", + "metadata": {}, + "outputs": [], + "source": [ + "!g++ -Wall -Wextra getMag.cpp" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "00684f47", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "|-2| = 2\n", + "|3.5| = 3.5\n", + "|12.34| = 12.34\n" + ] + } + ], + "source": [ + "!./a.out" + ] + }, + { + "cell_type": "markdown", + "id": "6631c752", + "metadata": {}, + "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", + "\n", + "Writing longer functions will become irksome, also, due to the line continuation stuff. *(and no syntax high-lighting or indentation ... by editors).*\n", + "\n", + "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", + "metadata": {}, + "source": [ + "### Generic Programming\n", + "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.\n", + "\n", + "From <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", + "\n", + "In C++ the approach to support generic programming is to use **templates**." + ] + }, + { + "cell_type": "markdown", + "id": "c9b5ee37", + "metadata": {}, + "source": [ + "## C++ Template Basics\n", + "\n", + "So how would we takle our problem with templates?\n", + "\n", + "Instead of multiple free-functions we implement a **single templated version** of it:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "90ddfa90", + "metadata": {}, + "outputs": [], + "source": [ + "template< typename T >\n", + "T getMagnitude( T value ) {\n", + " return value > static_cast< T >( 0 ) ? value : -value;\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "e2df86d3", + "metadata": {}, + "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): " + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "f5be2836", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "|-5| = 5" + ] + } + ], + "source": [ + "#include <iostream>\n", + "short s = -5;\n", + "std::cout << \"|\" << s << \"| = \" << getMagnitude( s );" + ] + }, + { + "cell_type": "markdown", + "id": "740ee0bd", + "metadata": {}, + "source": [ + "---\n", + "A closer look at the **function template**:\n", + "\n", + "```c++\n", + "template< typename T >\n", + "T 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" + ] + }, + { + "cell_type": "markdown", + "id": "d6754844-ef2d-496e-adab-1367a463c19f", + "metadata": {}, + "source": [ + "---\n", + "Now let's take a look at the **instantiation**:" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "8f2ab60c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting withTemplates.cpp\n" + ] + } + ], + "source": [ + "%%file withTemplates.cpp\n", + "\n", + "template< typename T >\n", + "T getMagnitude( T value ) {\n", + " return value > static_cast< T >( 0 ) ? value : -value;\n", + "}\n", + " \n", + "int 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", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "96551727-c1b0-4b97-9bff-11e9eeac731e", + "metadata": {}, + "outputs": [], + "source": [ + "!g++ -save-temps -c withTemplates.cpp" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "d3e0f1fc-f85a-4adc-a63f-ba7fdea02a2d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0000000000000000 T main\n", + "0000000000000000 W double getMagnitude<double>(double)\n", + "0000000000000000 W float getMagnitude<float>(float)\n", + "0000000000000000 W long getMagnitude<long>(long)\n", + "0000000000000000 W short getMagnitude<short>(short)\n" + ] + } + ], + "source": [ + "!nm -C withTemplates.o" + ] + }, + { + "cell_type": "markdown", + "id": "d63382c0-e766-422b-ba97-7824de507c3a", + "metadata": {}, + "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", + "\n", + "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 internally." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "9c620720-b4cc-46a0-bde0-57452bcd3a0b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "# 1 \"withTemplates.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 \"withTemplates.cpp\"\n", + "\n", + "template< typename T >\n", + "T getMagnitude( T value ) {\n", + " return value > static_cast< T >( 0 ) ? value : -value;\n", + "}\n", + "\n", + "int 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", + "}\n" + ] + } + ], + "source": [ + "!cat withTemplates.ii" + ] + }, + { + "cell_type": "markdown", + "id": "5cfc8599", + "metadata": {}, + "source": [ + "We can, however, also **explicitely** request the compiler to instantiate a version for a specific template argument:" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "38aa85e7-83d9-4ae0-ac05-80cf187ee9f3", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting withTemplates.cpp\n" + ] + } + ], + "source": [ + "%%file withTemplates.cpp\n", + "\n", + "template< typename T >\n", + "T getMagnitude( T value ) {\n", + " return value > static_cast< T >( 0 ) ? value : -value;\n", + "}\n", + "\n", + "// explicit instantiation\n", + "template float getMagnitude( float );\n", + "\n", + "int main() {\n", + "\n", + " // implicit instantiation\n", + " getMagnitude( -2 );\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "76bfe507-bc01-457a-aeb5-38e2db572cac", + "metadata": {}, + "outputs": [], + "source": [ + "!g++ -save-temps -c withTemplates.cpp" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "e707d5e2-6d8d-4ee9-9046-b749d154146b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0000000000000000 T main\n", + "0000000000000000 W float getMagnitude<float>(float)\n", + "0000000000000000 W int getMagnitude<int>(int)\n" + ] + } + ], + "source": [ + "!nm -C withTemplates.o" + ] + }, + { + "cell_type": "markdown", + "id": "76ecc704-ac09-4343-b561-7817373aa1c9", + "metadata": {}, + "source": [ + "When might explicit instantiation be required?\n", + "\n", + "Let us modify our example to have the usual structure of *header file* (.hpp) and *source code file* (.cpp) and a separate *driver file*:" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "a854c3ce-1865-4ec1-b092-87be2a50d13f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting withTemplates.cpp\n" + ] + } + ], + "source": [ + "%%file withTemplates.cpp\n", + "\n", + "template< typename T >\n", + "T getMagnitude( T value ) {\n", + " return value > static_cast< T >( 0 ) ? value : -value;\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "b3b433db-8509-43fb-9946-579ffd4c5dfb", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting withTemplates.hpp\n" + ] + } + ], + "source": [ + "%%file withTemplates.hpp\n", + "\n", + "// only a prototype\n", + "template< typename T > T getMagnitude( T value );" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "c96bbc17-3771-453b-9544-eae96dd936f0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting driver.cpp\n" + ] + } + ], + "source": [ + "%%file driver.cpp\n", + "\n", + "#include \"withTemplates.hpp\"\n", + "int main() {\n", + " getMagnitude( -1.2345f );\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "0cea5aa2-240b-493c-8afc-c560b0dff82c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/tmp/ccYQKyzG.o: In function `main':\n", + "driver.cpp:(.text+0xd): undefined reference to `float getMagnitude<float>(float)'\n", + "collect2: error: ld returned 1 exit status\n" + ] + } + ], + "source": [ + "!g++ driver.cpp" + ] + }, + { + "cell_type": "markdown", + "id": "976e6ef4-ce58-4a4f-acf9-bff9d122923d", + "metadata": {}, + "source": [ + "Okay, that is not different from the usual. The source code of `getMagnitude()` is inside `withTemplates.cpp`. So let us also compile this source code file:" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "e98425fb-dc85-4e89-9f9b-dc310b1c65bb", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/tmp/ccXICvwu.o: In function `main':\n", + "driver.cpp:(.text+0xd): undefined reference to `float getMagnitude<float>(float)'\n", + "collect2: error: ld returned 1 exit status\n" + ] + } + ], + "source": [ + "!g++ driver.cpp withTemplates.cpp" + ] + }, + { + "cell_type": "markdown", + "id": "0ace12fa-d5a8-48ab-8d9b-250c71847812", + "metadata": {}, + "source": [ + "Still a problem! Why's that?" + ] + }, + { + "cell_type": "markdown", + "id": "bf20a5c9-5d48-405f-861e-afc7d699ff41", + "metadata": {}, + "source": [ + "---\n", + "\n", + "\n", + "*intentionally left blank ;-)*\n", + "\n", + "\n", + "---" + ] + }, + { + "cell_type": "markdown", + "id": "1517f452-ef0e-471a-82c0-880e829a51ff", + "metadata": {}, + "source": [ + "When we compile the driver the compiler will recognise that it need a version of `getMagnitude()` for `float`:" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "846d3074-53c4-4dfe-94af-43b82f49d0a8", + "metadata": {}, + "outputs": [], + "source": [ + "!g++ -c driver.cpp" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "7f84b616-97d9-4ce0-a588-7bed26c4b4aa", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " U _GLOBAL_OFFSET_TABLE_\n", + "0000000000000000 T main\n", + " U float getMagnitude<float>(float)\n" + ] + } + ], + "source": [ + "!nm -C driver.o" + ] + }, + { + "cell_type": "markdown", + "id": "43c992a6-7dca-4aab-8293-328b0cd8bf76", + "metadata": {}, + "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. (Just as in a non-template case)\n", + "\n", + "Okay. So now let us compile the source code file and check the contents of the resulting object file:" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "15c7f98e-33fd-4bca-8293-5a19352c43ac", + "metadata": {}, + "outputs": [], + "source": [ + "!g++ -c withTemplates.cpp" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "5f6a4521-affc-4147-a33a-a7fd4f6051ce", + "metadata": {}, + "outputs": [], + "source": [ + "!nm -C withTemplates.o" + ] + }, + { + "cell_type": "markdown", + "id": "b955ee26-e340-44e5-a264-66beda062321", + "metadata": {}, + "source": [ + "Oops. Nothing. Why?\n", + "\n", + "Because in the source code file no template instance is required and the template function itself cannot be compiled without an argument for the datatype!" + ] + }, + { + "cell_type": "markdown", + "id": "6bd45ab9-c3b9-4ec2-b093-1a2f327a0526", + "metadata": {}, + "source": [ + "---\n", + "Splitting declaration and definition of a template function requires us to use explicit instantiation." + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "e0aa1181-d4b2-4fc1-95fe-ead0f86b2d5b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting withTemplates.cpp\n" + ] + } + ], + "source": [ + "%%file withTemplates.cpp\n", + "\n", + "template< typename T >\n", + "T getMagnitude( T value ) {\n", + " return value > static_cast< T >( 0 ) ? value : -value;\n", + "}\n", + "\n", + "template float getMagnitude( float );" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "e86d0de4-3e7e-48d1-8b2f-3a2b29e44842", + "metadata": {}, + "outputs": [], + "source": [ + "!g++ -save-temps driver.cpp withTemplates.cpp" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "380b4117-4a81-45dc-a578-88f233d8726e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0000000000000000 W float getMagnitude<float>(float)\n" + ] + } + ], + "source": [ + "!nm -C withTemplates.o" + ] + }, + { + "cell_type": "markdown", + "id": "9368884e", + "metadata": {}, + "source": [ + "### Template Classes\n", + "\n", + "Naturally in C++ free-functions are not the only aspect we can templatise. We can also do so for member functions of classes and complete classes. The latter we have already seen e.g. with the STL containers." + ] + }, + { + "cell_type": "markdown", + "id": "f91b42be", + "metadata": {}, + "source": [ + "As an example let us write a small wrapper class for a static array (note that the usefull variant of this would be `std::array` from the STL)." + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "5d7941c5", + "metadata": {}, + "outputs": [], + "source": [ + "template< typename T, int N >\n", + "struct StaticArray {\n", + " int getSize() { return N; };\n", + " T data [N];\n", + "};" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "69a7c099", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "StaticArray< double, 3 > shortVec;\n", + "shortVec.getSize()" + ] + }, + { + "cell_type": "markdown", + "id": "db743abf", + "metadata": {}, + "source": [ + "Observations:\n", + "1. The syntax for the template class definition is similar to that of template functions. We have the normal class part with a `template< 'argument list' >` in front of it.\n", + "1. Template parameters are not restricted to type parameters. We can also use **non-type parameters**:\n", + " - integer types (`int`, `short`, `bool`, ...)\n", + " - floating-point types (since C++20)\n", + " - pointers and references\n", + "the argument for instantiation then is a value of that type.\n", + "1. We do not need to store the size `N` of the array in the class as an attribute. Instead we can use the template parameter which will be replaced by the argument value provided at instantiation.\n", + "1. Contrary to our previous examples we need to specifiy the template arguments explicitely for the instantiation to work. The compiler cannot determine them from our use of the default constructor. So **CTAD (Class Template Argument Deduction)** will not work." + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "a2978a5c", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[1minput_line_13:2:2: \u001b[0m\u001b[0;1;31merror: \u001b[0m\u001b[1muse of class template 'StaticArray' requires template arguments\u001b[0m\n", + " StaticArray longVec;\n", + "\u001b[0;1;32m ^\n", + "\u001b[0m\u001b[1minput_line_8:2:8: \u001b[0m\u001b[0;1;30mnote: \u001b[0mtemplate is declared here\u001b[0m\n", + "struct StaticArray {\n", + "\u001b[0;1;32m ^\n", + "\u001b[0m" + ] + }, + { + "ename": "Interpreter Error", + "evalue": "", + "output_type": "error", + "traceback": [ + "Interpreter Error: " + ] + } + ], + "source": [ + "StaticArray longVec;" + ] + }, + { + "cell_type": "markdown", + "id": "a8f52ca7", + "metadata": {}, + "source": [ + "### Lazy vs Eager Instantiation" + ] + }, + { + "cell_type": "markdown", + "id": "9f21c5d4", + "metadata": {}, + "source": [ + "In C++ **implicit instantiation is lazy**. In the case of a template class this means that only member functions that are not called do not get instantiated! \n", + "\n", + "**Explicit instantiation**, on the other hand, is eager.\n", + "\n", + "We can see this from the following (slightly extended) example taken from \n", + "Rainer Grimm's blog <a href=\"https://www.grimm-jaud.de/index.php/blog\">Modernes C++ in der Praxis</a>." + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "a06c3b23", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting lazy.cpp\n" + ] + } + ], + "source": [ + "%%file lazy.cpp\n", + "\n", + "#include <cmath>\n", + "#include <string>\n", + "\n", + "template< typename T >\n", + "struct Number {\n", + " int absValue() {\n", + " return std::abs( val );\n", + " }\n", + " T val{};\n", + "};\n", + "\n", + "// force explicit instantiation of struct (this is eager!) (A)\n", + "// template struct Number< std::string >;\n", + "\n", + "int main() {\n", + "\n", + " // results in implicit instantiation (this is lazy!)\n", + " Number< std::string > num;\n", + "\n", + " // results in instantiation of member function (B)\n", + " // num.absValue();\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "06c4ffb9", + "metadata": {}, + "outputs": [], + "source": [ + "!g++ lazy.cpp" + ] + }, + { + "cell_type": "markdown", + "id": "c89daa16", + "metadata": {}, + "source": [ + "Let us check this for our previous example, too." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "4fd246ab", + "metadata": {}, + "outputs": [], + "source": [ + "#include <iostream>\n", + "\n", + "template< typename T, int N >\n", + "struct StaticArray {\n", + " int getSize() { return N; };\n", + " T data[N];\n", + "};\n", + "\n", + "int main() {\n", + "\n", + " StaticArray< float, 5 > shortVec;\n", + " StaticArray< short, 100 > longVec;\n", + " StaticArray< float, 5 > shortVec2;\n", + " std::cout << longVec.getSize();\n", + " \n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "1a01b8b8", + "metadata": {}, + "source": [ + "Questions:\n", + "- Will `getSize()` be instantiated for `StaticArray< float, 5 >`?\n", + "- How many times will `StaticArray< float, 5 >` be instantiated?\n", + "In order to answer these let us feed the code to the source-to-source translator\n", + "<a href=\"https://cppinsights.io\">C++ Insights</a>. This gives us a view on what the compiler would do." + ] + }, + { + "cell_type": "markdown", + "id": "ca2aa233", + "metadata": {}, + "source": [ + "<img align=\"left\" src=\"../images/cppInsights01.png\" />" + ] + }, + { + "cell_type": "markdown", + "id": "c9580c48", + "metadata": {}, + "source": [ + "Answers:\n", + "- The instantiation of `StaticArray< float, 5 >` is implicit. Thus, it is lazy. The compiler knows that the member function `getSize()` exists and what its prototype is, but it will not generate machine code for it, as it is never called.\n", + "- The class `StaticArray< float, 5 >` itself represents a datatype. While we can have multiple objects of this type, the template will only be instantiated once, for the same arguments.</br>\n", + "(Note: That's not necessarily true for multiple compilation units! If multiple instances get generated the linker takes care of uniqueness.)*" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "da055e27", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "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": 4, + "nbformat_minor": 5 +} -- GitLab