Skip to content

Commit

Permalink
Lecture 4, will be tested today
Browse files Browse the repository at this point in the history
Crazy-Rich-Meghan committed Dec 5, 2023
1 parent 1a8e85e commit fe41501
Showing 1 changed file with 834 additions and 0 deletions.
834 changes: 834 additions & 0 deletions notebooks/lecture4.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,834 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "35dcd074",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Object-oriented scientific programming with C++\n",
"\n",
"Matthias Möller, Jonas Thies, Cálin Georgescu, Jingya Li (Numerical Analysis, DIAM)\n",
"\n",
"Lecture 4"
]
},
{
"cell_type": "markdown",
"id": "3a57f6c5",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## <center>Overview</center>\n",
"Last lecture we started with **template meta programming**\n",
"- Implement type-independent functionality\n",
" - Class templates/function templates\n",
" - Generic attributes being able to hold arbitrary data type\n",
" - Generic member function realizing the default behaviour\n",
"- Implement specialized variants of member functions to support special behaviour, e.g., dot product for complex types\n",
"- Instantiate class with concrete types (double, float, etc.)"
]
},
{
"cell_type": "markdown",
"id": "8e82d027",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## <center>Instantiate class with concrete types (double, float, etc.)</center>\n",
"C++ allows you to **partially specialize** class templates\n",
"```C++\n",
"template<typename S>\n",
"std::complex<S> Vector<std::complex<S> >::\n",
"dot(const Vector<std::complex<S> > other) const { std::complex<S> d=0;\n",
"for (auto i=0; i<n; i++)\n",
" d += data[i]*std::conj(other.data[i]);\n",
" return d;\n",
"}\n",
"```\n",
"Note that this code will not compile. We will see why and learn remedies. Welcome to where template magic begins!"
]
},
{
"cell_type": "markdown",
"id": "9c8204d4",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## <center>Overview</center>\n",
"Today, **advanced template meta programming**\n",
"- Full template specialization of complete classes\n",
"- Full template specialization of individual member functions\n",
"- Partial template specialization of class templates\n",
"- Type traits\n",
"- SFINAE paradigm"
]
},
{
"cell_type": "markdown",
"id": "390afba6",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## <center>Template specialization</center>\n",
"Type-independent **default implementation**\n",
"```C++\n",
"template<typename T, typename I>\n",
"struct Demo {\n",
" static void info() {\n",
" std::cout << “Generic info“ << std::endl; }\n",
" static void test() {\n",
" std::cout << “Generic test“ << std::endl; }\n",
"};\n",
"```\n",
"This implementation is used whenever there is no (partial) specialization of the `struct Demo` and/oritsfunctions"
]
},
{
"cell_type": "markdown",
"id": "c300db4a",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## <center>Class template specialization</center>\n",
"**Task:** implement a template specialization of the entire\n",
"`struct Demo` for `T=float` and `I=long`\n",
"\n",
"Note that template specialization does not imply class inheritance; that is, all attributes/functions that you want to have in a specialized class have to be implemented\n",
"\n",
"Think of class specialization as implementing a new independent `struct Demo<float, long>` thatjusthasthe same name as the generic `struct Demo<T,I>`"
]
},
{
"cell_type": "markdown",
"id": "ad514241",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## <center>Class template specialization</center>\n",
"**Fully specialized** implementation of the entire **structure**\n",
"```C++\n",
"template<>\n",
"struct Demo<float, long>\n",
"{\n",
" static void info() {\n",
" std::cout << “Fully specialized info“ << std::endl; }\n",
" static void test() {\n",
" std::cout << “Fully specialized test“ << std::endl; }\n",
"};\n",
"```\n",
"\n",
"This implementation is used for the special case\n",
"\n",
"```C++\n",
"Demo<float,long>::info() -> class specialization \n",
"Demo<float,long>::test() -> class specialization\n",
"```"
]
},
{
"cell_type": "markdown",
"id": "aab2b26c",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## <center>Class template specialization</center>\n",
"**Fully specialized** implementation of the entire **structure**\n",
"but without a member function test()\n",
"```C++\n",
"template<>\n",
"struct Demo<float, long>\n",
"{\n",
" static void info() {\n",
" std::cout << “Fully specialized info“ << std::endl; }\n",
"};\n",
"```\n",
"This implementation yields a compiler error\n",
"\n",
"```C++\n",
"Demo<float,long>::info() -> class specialization\n",
"Demo<float,long>::test() // compiler error \n",
"```"
]
},
{
"cell_type": "markdown",
"id": "6cb3b556",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## <center>Class-function template specialization</center>\n",
"**Task:** implement a specialization of the member function `info()` for `T=float` and `I=long`\n",
"\n",
"Since we only implement a specialization for the individual function `info()`, the implementation of function `test()` from the non-specialized `struct Demo` remains available\n",
"\n",
"Think of member function specialization as superseding individual member functions by specialized variants"
]
},
{
"cell_type": "markdown",
"id": "40b21ae7",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## <center>Class-function template specialization</center>\n",
"\n",
"**Fully specialized** implementation of **function** `info()`\n",
"```C++\n",
"template<>\n",
"void Demo<double, long>::info() {\n",
" std::cout << „Fully specialised info“ << std::endl; } \n",
"}\n",
"```\n",
"This implementation provides the specialization of function\n",
"`info()` and the generic implementation of function `test()`\n",
"```C++\n",
"Demo<double,long>::info() -> class-function specialization\n",
"Demo<double,long>::test() -> generic\n",
"```"
]
},
{
"cell_type": "markdown",
"id": "7f320757",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## <center>Class-function template specialization</center>\n",
"**Fully specialized** implementation of function `info()`\n",
"```C++\n",
"template<>\n",
"void Demo<double, long>::info() {\n",
" std::cout << „Fully specialised info“ << std::endl; } \n",
"}\n",
"```\n",
"This implementation provides the specialization of function\n",
"`info()` andthegeneric implementation of function `test()`\n",
"\n",
"```C++\n",
"Demo<double,long>::info() -> class-function specialization\n",
"Demo<double,long>::test() -> generic\n",
"```"
]
},
{
"cell_type": "markdown",
"id": "6948a035",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## <center>Class template partial specialization</center>\n",
"\n",
"**Task:** implement a specialization of the entire `struct Demo` for `T=float` and arbitrary template parameter value `I`"
]
},
{
"cell_type": "markdown",
"id": "b26bf024",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## <center>Class template partial specialization</center>\n",
"**Partially specialized** implementation of the **structure**\n",
"```C++\n",
"template<typename I>\n",
" struct Demo<double, I>\n",
" {\n",
" static void info() {\n",
" std::cout << „Partially specialized info“ << std::endl; }\n",
" static void test() {\n",
" std::cout << „Partially specialized test“ << std::endl; }\n",
"};\n",
"```\n",
"This implementation is used for the special case\n",
"\n",
"```C++\n",
"Demo<double,int>::info() -> partial class specialization\n",
"Demo<double,int>::test() -> partial class specialization\n",
"```"
]
},
{
"cell_type": "markdown",
"id": "be640e26",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## <center>Class template partial specialization</center>\n",
"**Task:** implement a specialization of member function `info()` for `T=float` and arbitrary template parameter value `I`\n",
"\n",
"Partial function template specialization is not **possible in C++**\n",
"```C++\n",
"template<typename I>\n",
"void Demo<float, I>::info() {...}\n",
"```\n",
"\n",
"Stay tuned, there are tricks to solve this problem"
]
},
{
"cell_type": "markdown",
"id": "0d8f79de",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## <center>Summary template specialization</center>\n",
"Given a templated class with member functions\n",
"- Entire class can be fully or partially specialized\n",
"- Individual member functions can fully specialized\n",
"- Individual member functions **cannot** be partially specialized\n",
"\n",
"Full/partial class specialization is like implementing a new individual class that can be accessed by the same name\n",
"\n",
"Full function specialization is like superseding individual member functions by specialized variants"
]
},
{
"cell_type": "markdown",
"id": "3daf7ddd",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## <center>Quiz</center>\n",
"Remember the specialized dot product for complex-valued\n",
"vectors from the previous session, will this work?\n",
"\n",
"```C++\n",
"template<typename T> class Vector {\n",
" T dot(const Vector<T>& other) const {...}\n",
"};\n",
"template<typename S> std::complex<S> \n",
" Vector<std::complex<S> >::\n",
" dot(const Vector<std::complex<S> > other) const {\n",
" std::complex<S> d=0;\n",
" for (auto i=0; i<n; i++)\n",
" d += data[i]*std::conj(other.data[i]);\n",
" return d;\n",
"} \n",
"```"
]
},
{
"cell_type": "markdown",
"id": "1e5b1bf8",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## <center>SFINAE paradigm</center>\n",
"C++ allows us to write **overloaded functions with different**\n",
"input parameter lists, e.g.,\n",
"```C++\n",
"static void info() {...}\n",
"static void info(int i) {...}\n",
"```\n",
"It is, however, **not** allowed to overload functions that only differ in the type of their return parameter, e.g.,\n",
"```C++\n",
"static void info() {...}\n",
"static int info() {...}\n",
"```"
]
},
{
"cell_type": "markdown",
"id": "f22ba5b8",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## <center>SFINAE paradigm</center>\n",
"C++11 standard states:\n",
"\n",
"<i>If a substitution results in an invalid type or expression, type deduction fails. An invalid type or expression is one that would be ill-formed if written using the substituted arguments. Only invalid types and expressions in the immediate context of the function type and its template parameter types can result in a deduction failure.</i>\n",
"\n",
"**SFINAE:** <span style=color:red;>S</span>ubstitution <span style=color:red;>F</span>ailure <span style=color:red;>I</span>s <span style=color:red;>N</span>ot <span style=color:red;>A</span>n <span style=color:red;>E</span>rror"
]
},
{
"cell_type": "markdown",
"id": "e3dee20b",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## <center>SFINAE paradigm</center>\n",
"C++11 standard rephrased for our purpose:\n",
"\n",
"<i>If a template substitution leads to invalid code then the compiler must not throw an error but look for another candidate (i.e. the second templated implementation of our function); <b>an error is just thrown if no other candidate can be found</b> so that the function call remains unresolved</i>"
]
},
{
"cell_type": "markdown",
"id": "be2aa4cf",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## <center>SFINAE paradigm</center>\n",
"**SFINAE:** <span style=color:red;>S</span>ubstitution <span style=color:red;>F</span>ailure <span style=color:red;>I</span>s <span style=color:red;>N</span>ot <span style=color:red;>A</span>n <span style=color:red;>E</span>rror\n",
"\n",
"- Write multiple implementations of the same function with\n",
" - the **same name** and\n",
" - the **same input parameters**\n",
"- Ensure – via template meta programming – that **exactly one** at a time results in **valid code** upon substitution of the template parameters and **all other** candidates yield **invalid expressions**"
]
},
{
"cell_type": "markdown",
"id": "d7007a07",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## <center>Intermezzo: Traits</center>\n",
"Consider the `is_int` **function** from the previous assignment\n",
"```C++\n",
"template<typename T>\n",
"bool is_int(T a) { return false; }\n",
"template<>\n",
"bool is_int<int>(int a) { return true; }\n",
"```\n",
"\n",
"This function returns true/false depending on the type of the parameter passed via explicit template specialisation\n",
"\n",
"We look for an even more elegant solution without the need to call a function and pass a parameter at all"
]
},
{
"cell_type": "markdown",
"id": "709a9bef",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## <center>Intermezzo: Traits</center>\n",
"Consider the templated `is_int` **structure** with specialization\n",
"```C++\n",
"template<typename T>\n",
"struct is_int\n",
"{\n",
" const static bool value = false;\n",
"};\n",
"template<>\n",
"struct is_int<int>\n",
"{\n",
" const static bool value = true;\n",
"};\n",
"```"
]
},
{
"cell_type": "markdown",
"id": "3577d66d",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## <center>Intermezzo: Traits</center>\n",
"Detect if a given type is `int` without passing a parameter\n",
"```C++\n",
"std::cout << is_int<int>::value << std::endl;\n",
"std::cout << is_int<double>::value << std::endl;\n",
"```\n",
"The `is_int` **type trait** can be used in templated functions\n",
"```C++\n",
"template<typename T>\n",
"void test(T a)\n",
"{\n",
" if (is_int<T>::value)\n",
" std::cout << „Integer :“ << a << std::endl;\n",
" else\n",
" std::cout << „Non-Int :“ << a << std::endl;\n",
"}\n",
"```"
]
},
{
"cell_type": "markdown",
"id": "5ab6d885",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## <center>Intermezzo: Traits</center>\n",
"The `is_int` **type trait** is evaluated at compile time in contrast to the `is_int()` **function** which (theoretically) might trigger an extra function call at run time (slow!)\n",
"\n",
"A smart compiler will eliminate the if-else clause\n",
"\n",
"```C++\n",
"void test(int a)\n",
" {\n",
" if (is_int<T>::value)\n",
" std::cout << \"Integer :\" << a << std::endl;\n",
" else\n",
" std::cout << \"Non-Int :\" << a << std::endl;\n",
"}\n",
"```"
]
},
{
"cell_type": "markdown",
"id": "7e5e9d04",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## <center>Intermezzo: Traits</center>\n",
"C++ brings many **type traits** via `#include <type_traits>`\n",
"<table border=\"1\">\n",
" <tr>\n",
" <th>Function</th>\n",
" <th>Description</th>\n",
" </tr>\n",
" <tr>\n",
" <td>is_class&lt;T&gt;</td>\n",
" <td>Type T is of class type</td>\n",
" </tr>\n",
" <tr>\n",
" <td>is_const&lt;T&gt;</td>\n",
" <td>Type T has const qualifier</td>\n",
" </tr>\n",
" <tr>\n",
" <td>is_floating_point&lt;T&gt;</td>\n",
" <td>Type T is floating point (float, double, long)</td>\n",
" </tr>\n",
" <tr>\n",
" <td>is_fundamental&lt;T&gt;</td>\n",
" <td>Type T is of fundamental type (int, double, ...)</td>\n",
" </tr>\n",
" <tr>\n",
" <td>is_integral&lt;T&gt;</td>\n",
" <td>Type T is of integral type (int, long int, ...)</td>\n",
" </tr>\n",
" <tr>\n",
" <td>is_pointer&lt;T&gt;</td>\n",
" <td>Type T is of pointer type</td>\n",
" </tr>\n",
"</table>\n",
"\n",
"For a complete list of standard type traits look at:http://www.cplusplus.com/reference/type_traits/"
]
},
{
"cell_type": "markdown",
"id": "9c0b9ee8",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## <center>Intermezzo: Type traits</center>\n",
"The aforementioned C++ **standard type traits** provide\n",
"- Member constants:\n",
" `value (=true/false)`\n",
"- Member types:\n",
" `value_type (=bool)`\n",
" \n",
" `type (=true_type/false_type)`\n",
"Member constants/types can be directly accessed\n",
"```C++\n",
"is_fundamental<int>::value // true\n",
"is_fundamental<int>::value_type // bool \n",
"```"
]
},
{
"cell_type": "markdown",
"id": "4fccc3ef",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## <center>Intermezzo: Types Traits</center>\n",
"C++ provides type traits that **operate on the type**\n",
"```C++\n",
"typedef add_const<int> A // const int\n",
"typedef add_const<const int> B // const int (unchanged)\n",
" \n",
"typedef add_pointer<int> C // int*\n",
"typedef add_pointer<const int> D // const int*\n",
"typedef add_pointer<int&> E // int*\n",
"typedef add_pointer<int*> F // int**\n",
"typedef add_pointer<int(int)> G // int(*)int\n",
"```"
]
},
{
"cell_type": "markdown",
"id": "30ccb64c",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## <center>Intermezzo: Types Traits</center>\n",
"C++ provides type traits that **operate on the type**\n",
"\n",
"```C++\n",
"typedef remove_const<int> A // int (unchanged)\n",
"typedef remove_const<const int> B // int\n",
"\n",
"typedef remove_pointer<int> C //int\n",
"typedef remove_pointer<int*> D //int\n",
"typedef remove_pointer<int**> E //int*\n",
"typedef remove_pointer<const int> F //const int\n",
"typedef remove_pointer<const int*> G //const int\n",
"typedef remove_pointer<int* const> H //int\n",
"```"
]
},
{
"cell_type": "markdown",
"id": "1855cf1b",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## <center>Intermezzo: Types Traits</center>\n",
"C++ provides type traits that **operate on two types:**\n",
"Check if two types are **exactly** the same (including qualifiers)\n",
"\n",
"```C++\n",
"bool is_same<A, B>::value\n",
"\n",
"bool is_same<int, int>::value // true\n",
"bool is_same<int, const int>::value // false\n",
"bool is_same<remove_const<int>,\n",
" remove_const<const int> >::value // true\n",
"```"
]
},
{
"cell_type": "markdown",
"id": "15351b18",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## <center>Intermezzo: Type Traits</center>\n",
"C++ provides type traits that **operate on two types:**\n",
"\n",
"Check if type B is derived from type A\n",
"\n",
"```C++\n",
"struct A {};\n",
"struct B : A {};\n",
"bool is_base_of<A, B>::value\n",
" \n",
"bool is_base_of<A, A>::value // true\n",
"bool is_base_of<A, B>::value // true\n",
"bool is_base_of<B, A>::value // false\n",
"bool is_base_of<B, B>::value // true\n",
"```"
]
},
{
"cell_type": "markdown",
"id": "b821d37a",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## <center>Intermezzo: Type Traits</center>\n",
"C++ provides type trait to **enable types conditionally**\n",
"```C++\n",
"template<typename T>\n",
"typename std::enable_if<std::is_integral<T>::value,\n",
" bool>::type\n",
"is_odd(T i) { return bool(i%2); }\n",
"int i=2;\n",
"cout << „i is odd :“ << is_odd(i) << endl;\n",
"```\n",
"If `is_odd` is called with an **integral type** (e.g., `int`) the compiler\n",
"expands the above templated function as follows\n",
"\n",
"```C++\n",
"bool is_odd(int i) { return bool(i%2); }\n",
"```"
]
},
{
"cell_type": "markdown",
"id": "211c8f0f",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## <center>Intermezzo: Type Traits</center>\n",
"C++ provides type trait to **enable types conditionally**\n",
"```C++\n",
"template<typename T>\n",
"typename std::enable_if<std::is_integral<T>::value,\n",
" bool>::type\n",
"is_odd(T i) { return bool(i%2); }\n",
"float i=2;\n",
"cout << „i is odd :“ << is_odd(i) << endl;\n",
"```\n",
"\n",
"If `is_odd` is called with a **non-integral type** (e.g., `float`) the compiler expands the above templated function as follows\n",
"\n",
"```C++\n",
"is_odd(float i) { return bool(i%2); } // compiler error\n",
"```"
]
},
{
"cell_type": "markdown",
"id": "f8522388",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## <center>SFINAE paradigm</center>\n",
"**SFINAE:** <span style=color:red;>S</span>ubstitution <span style=color:red;>F</span>ailure <span style=color:red;>I</span>s <span style=color:red;>N</span>ot <span style=color:red;>A</span>n <span style=color:red;>E</span>rror\n",
"\n",
"- Write multiple implementations of the same function with\n",
" - the **same name** and\n",
" - the **same input parameters**\n",
"- Ensure using the `enable_if` **type trait** that exactly one at a time results in **valid code** upon substitution of template parameters and **all other** candidates yield **invalid expressions**"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "18b86abf",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "6d59f4ce",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "3647a872",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "89021cec",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "0642d6a0",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"celltoolbar": "Slideshow",
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.5"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

0 comments on commit fe41501

Please sign in to comment.