diff --git a/notebooks/08_Functors+Lambdas.ipynb b/notebooks/08_Functors+Lambdas.ipynb
index 01e92b0c869de2c2d7b0e0633d8f52ec81d76753..5c165fcbb307ead6a62956b8c01c5db3d1eb65be 100644
--- a/notebooks/08_Functors+Lambdas.ipynb
+++ b/notebooks/08_Functors+Lambdas.ipynb
@@ -1,1148 +1 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "id": "789d7a72",
-   "metadata": {},
-   "source": [
-    "# Functors, Lambdas and std::function"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "008aa425",
-   "metadata": {},
-   "source": [
-    "#### Function Pointers\n",
-    "In a previous example we had implemented a function to compare to objects of type ```myPair```."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 1,
-   "id": "96f5ab84",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "class myPair;\n",
-    "bool cmp( const myPair& left, const myPair& right );"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "ea6fcef6",
-   "metadata": {},
-   "source": [
-    "We needed that function to be able to create a set of ```myPair```'s.\n",
-    "\n",
-    "        std::set< myPair, decltype( cmp )* > pairs ( cmp );\n",
-    "What we pass to ```std::set```'s constructor is a **function pointer** of type\n",
-    "\n",
-    "        bool (*) ( const myPair&, const myPair& )"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "dc79e822",
-   "metadata": {},
-   "source": [
-    "***\n",
-    "- This way to work with functions is something that C++ inherited from C.\n",
-    "- Not only in the STL, but also in scientific programming we often have the case that we implement something, but want to leave some details to the user:  \n",
-    "  - Consider e.g. implementing an algorithm to approximate the integral\n",
-    "$$I = \\int_a^b f(x)\\, dx$$\n",
-    "  - When we code that we would like to leave the details of the integrand to be specified flexibly by the user.  \n",
-    "  - As with std::set we can let the user provide a function that we then call inside our code.\n",
-    "  - This is known as a **callback**.\n",
-    "- The main downside to using function (pointers) in this approach is that a free function is **stateless**. In order to influence its behaviour we have to pass arguments through its interface. That does not work nicely with the callback idea.\n",
-    "  - Note: We can add *state* to a function by making some of its local variables ```static```. See the ```accumulate``` examples.\n",
-    "  - However, a function is a global entity. Thus, there can always only be one state for it."
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "9ce08962",
-   "metadata": {},
-   "source": [
-    "#### Functors\n",
-    "In C++ we can as one alternative use a **function object**, a.k.a. **functor**. This is an object of a class that overloads the function call operator ```operator()```.\n",
-    "\n",
-    "##### **Example 1:**"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 2,
-   "id": "9bf146ec",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "#include <iostream>\n",
-    "\n",
-    "class greeter{\n",
-    "public:\n",
-    "  void operator() ( const std::string& str ) {\n",
-    "    std::cout << \"Greetings \" << str << std::endl;\n",
-    "  }\n",
-    "};"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 3,
-   "id": "b13aa200",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "int main() {\n",
-    "  greeter hello;\n",
-    "  hello( \"Class\" );\n",
-    "}"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 4,
-   "id": "f7a3701a",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Greetings Class\n"
-     ]
-    }
-   ],
-   "source": [
-    "main();"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "58a187c4",
-   "metadata": {},
-   "source": [
-    "***\n",
-    "Now that was a simple functor and did only demonstrate **how** it works and not **why** that approach can be advantageous.\n",
-    "\n",
-    "##### **Example 2:**  \n",
-    "In our second example we will use a stateful functor that allows to perform different binary operations. The type of operation will be passed via its constructor."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 5,
-   "id": "8c0f30c5",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "#include <iostream>\n",
-    "\n",
-    "class BinaryOperator {\n",
-    "\n",
-    "public:\n",
-    "\n",
-    "  typedef enum { ADD, MULT } type;\n",
-    "\n",
-    "  BinaryOperator() = delete;\n",
-    "  BinaryOperator( BinaryOperator::type op ) : whatToDo( op ) {};\n",
-    "\n",
-    "  int operator() ( int a, int b ) {\n",
-    "    switch( whatToDo ) {\n",
-    "    case ADD:\n",
-    "      return a+b;\n",
-    "    case MULT:\n",
-    "      return a*b;\n",
-    "    }\n",
-    "  }\n",
-    "\n",
-    "private:\n",
-    "  type whatToDo;\n",
-    "\n",
-    "};"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 6,
-   "id": "05517c3a-eb4b-4827-9f74-54abf0264cca",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "int main() {\n",
-    "\n",
-    "  int a = 2;\n",
-    "  int b = 3;\n",
-    "\n",
-    "  BinaryOperator adder( BinaryOperator::ADD );\n",
-    "  BinaryOperator multiplier( BinaryOperator::MULT );\n",
-    "\n",
-    "  std::cout << adder( a, b ) << std::endl;\n",
-    "  std::cout << multiplier( a, b ) << std::endl;\n",
-    "}"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 7,
-   "id": "2777a5a1-f8bc-4907-90e2-488967071529",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "5\n",
-      "6\n"
-     ]
-    }
-   ],
-   "source": [
-    "main();"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "6adaab27",
-   "metadata": {},
-   "source": [
-    "##### **Example 3:**  \n",
-    "So how would our set example for myPair look like with a functor?"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 8,
-   "id": "856ee747",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Overwriting functor.cpp\n"
-     ]
-    }
-   ],
-   "source": [
-    "%%file functor.cpp\n",
-    "\n",
-    "#include <iostream>\n",
-    "#include <set>\n",
-    "\n",
-    "struct myPair {\n",
-    "  myPair( int fir, int sec ) : fir_( fir ), sec_( sec ) {\n",
-    "    std::cout << \"(\" << fir_ << \",\" << sec_ << \") constructed\" << std::endl;\n",
-    "  };\n",
-    "  int fir_;\n",
-    "  int sec_;\n",
-    "};\n",
-    "\n",
-    "struct myCompare {\n",
-    "  bool operator() ( const myPair& left, const myPair& right ) const {\n",
-    "    int val1 = left.fir_ * left.fir_ + left.sec_ * left.sec_;\n",
-    "    int val2 = right.fir_ * right.fir_ + right.sec_ * right.sec_;\n",
-    "    return val1 < val2;\n",
-    "  }\n",
-    "};\n",
-    "\n",
-    "int main() {\n",
-    "\n",
-    "  myCompare cmp;\n",
-    "  std::set< myPair, myCompare > pairs( cmp );\n",
-    "\n",
-    "  myPair p1( 1, 2 );\n",
-    "  myPair p2( 3, 4 );\n",
-    "\n",
-    "  std::cout << std::boolalpha;\n",
-    "  std::cout << \"p1 < p2 is \" << cmp( p1, p2 ) << std::endl;\n",
-    "  std::cout << \"p2 < p1 is \" << cmp( p2, p1 ) << std::endl;\n",
-    "\n",
-    "  pairs.insert( p1 );\n",
-    "  pairs.insert( p2 );\n",
-    "\n",
-    "  pairs.emplace( 3, 4 );\n",
-    "  pairs.emplace( 5, 6 );\n",
-    "}"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 9,
-   "id": "4adb7f0b",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "!g++ -Wall -Wextra functor.cpp"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 10,
-   "id": "f9bfde7f",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "(1,2) constructed\n",
-      "(3,4) constructed\n",
-      "p1 < p2 is true\n",
-      "p2 < p1 is false\n",
-      "(3,4) constructed\n",
-      "(5,6) constructed\n"
-     ]
-    }
-   ],
-   "source": [
-    "!./a.out"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "c51deb94-f9c2-4a88-914b-ddf70f29601e",
-   "metadata": {},
-   "source": [
-    "#### std::function\n",
-    "\n",
-    "Quoting from cppreference:\n",
-    "> Class template std::function is a general-purpose polymorphic function wrapper. Instances of std::function can store, copy, and invoke any CopyConstructible Callable target -- functions, lambda expressions, bind expressions, or other function objects, as well as pointers to member functions and pointers to data members.\n",
-    ">\n",
-    "> The stored callable object is called the target of std::function. If a std::function contains no target, it is called empty. Invoking the target of an empty std::function results in std::bad_function_call exception being thrown. \n",
-    "\n",
-    "The functionality of ```std::function``` is quite useful especially in combination with lambda functions (see below)."
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "6c584ecb-10c3-4ff2-ab53-2a66c0963009",
-   "metadata": {},
-   "source": [
-    "##### **Example 4:**\n",
-    "Assign a simple free-function"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 1,
-   "id": "21120bbb-03a7-4048-97f4-0426c40c5bac",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "#include <iostream>\n",
-    "void sayIt() { std::cout << \"He said captain, I said wot\" << std::endl; }"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 2,
-   "id": "bab0ab95-e5fd-4368-b3c2-77bcb869cfe0",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "// generate an object of type std::function;\n",
-    "\n",
-    "// need this header file\n",
-    "#include <functional>\n",
-    "\n",
-    "// need to supply the prototype of the function/invocation that we want to target\n",
-    "std::function< void( ) > sensible;"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 3,
-   "id": "b4e3f68a-6c70-49e7-a04c-924804c4cb35",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "empty -> nothing to do!\n"
-     ]
-    }
-   ],
-   "source": [
-    "// std::function overloads 'operator bool' so we can check if anything is targetted, yet\n",
-    "if( !sensible ) {\n",
-    "    std::cout << \"empty -> nothing to do!\" << std::endl;\n",
-    "}"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 5,
-   "id": "c5b3e4d0-64b4-47c6-848f-f787bf9c0b17",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "He said captain, I said wot\n"
-     ]
-    }
-   ],
-   "source": [
-    "// now assign a target to our std::object\n",
-    "sensible = sayIt;\n",
-    "\n",
-    "// and perform the invocation\n",
-    "sensible();"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "1ad030ff-9527-4436-be80-72baf9ac7b29",
-   "metadata": {},
-   "source": [
-    "##### **Example 5:**\n",
-    "Now let us use a functor with a slightly more complicated interface"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 6,
-   "id": "ff8d558b-da83-46d9-9842-8e0d9d5ba56d",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "// that's our functor\n",
-    "struct Mult {\n",
-    "    int operator() ( int a, int b ) { return a*b; } \n",
-    "}"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 7,
-   "id": "b5790b96-bf62-4d6e-ad9c-e56839882728",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "6"
-      ]
-     },
-     "execution_count": 7,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "// if we want, we can alias our std::function type\n",
-    "using binaryOp = std::function< int(int,int) >;\n",
-    "\n",
-    "// now instantiate an object that targets the functor\n",
-    "binaryOp multiply = Mult();\n",
-    "\n",
-    "// note that we needed the () to differentiate between the invocation and the functor itself!\n",
-    "\n",
-    "multiply(2,3)"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "589b7083-7a36-4ff8-bdd0-c46f9994228c",
-   "metadata": {},
-   "source": [
-    "##### **Example 6:**\n",
-    "A member function of a class can also serve as target"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 9,
-   "id": "646b302f-cdf5-40ed-98f8-01d98a9b277a",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "struct ItemsInStore{\n",
-    "    int num;\n",
-    "    ItemsInStore() = delete;\n",
-    "    ItemsInStore( int num ) : num(num) {};\n",
-    "    void decrementAndShowRest() {\n",
-    "        std::cout << \"Only \" << --num << \" items left!\" << std::endl;\n",
-    "    }\n",
-    "};"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 10,
-   "id": "b56b370a-654f-4665-a86d-1b4a1497a813",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "std::function< void( ItemsInStore& ) > takeOne = &ItemsInStore::decrementAndShowRest;"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 11,
-   "id": "b267e62f",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Only 4 items left!\n",
-      "Only 3 items left!\n"
-     ]
-    }
-   ],
-   "source": [
-    "ItemsInStore candyBox( 5 );\n",
-    "takeOne( candyBox );\n",
-    "takeOne( candyBox );"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "9d2c9715",
-   "metadata": {},
-   "source": [
-    "#### Lambdas\n",
-    "Using *function pointers* or *functors* implies some significant coding overhead.\n",
-    "\n",
-    "C++11 introduced **lambda (functions)**, also known as **closures**, as a leight-weight alternative, that can be written inline in the source code."
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "41bbe5a3",
-   "metadata": {},
-   "source": [
-    "Let's start with an example"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 13,
-   "id": "24ad0ef1",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      " 1 4 9 16 25"
-     ]
-    }
-   ],
-   "source": [
-    "#include <vector>\n",
-    "#include <iostream>\n",
-    "#include <algorithm>\n",
-    "\n",
-    "std::vector< int > numbers{1,2,3,4,5};\n",
-    "\n",
-    "for_each( numbers.begin(), numbers.end(), []( int& n ) { n *= n; } );\n",
-    "\n",
-    "for( int v: numbers ) std::cout << \" \" << v;"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "ff3d112c",
-   "metadata": {},
-   "source": [
-    "The expression **`[]( int& n ) { n *= n; }`** is an *anonymous function*, so called, lambda, lambda expression, lambda function or closure.\n",
-    "\n",
-    "- The `(...)` part specifies the interface.\n",
-    "- If a lambda function does not return a value we can omit the return type.\n",
-    "- The `{...}` part is for the body of the function.\n",
-    "- The `[...]` part allows to *capture* variables from the current scope.\n",
-    "\n",
-    "lambda functions do not really provide extra functionality. We could accomplish the same with a free-function or a functor. In this sense they are only syntactic sugar, \"but of the sweetest kind\" (Rainer Grimm)."
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "5764a9c9",
-   "metadata": {},
-   "source": [
-    "##### Captures:\n",
-    "\n",
-    "The `[ ]` part of the lambda expression can contain a comma-separated list of stuff we want to *capture*. This allows using it inside the body of the lambda without explicitely passing it through the interface. There are also two *defaults* we can speficy:\n",
-    "\n",
-    "|       | effect |\n",
-    "|:-----:|:-------|\n",
-    "| &     | implicitly capture the used automatic variables by reference |\n",
-    "| :     | implicitly capture the used automatic variables by copy      |\n",
-    "| a     | capture a from surrounding scope by copy                     |\n",
-    "| &a    | capture a from surrounding scope by reference                |\n",
-    "\n",
-    "See e.g. <a href=\"https://en.cppreference.com/w/cpp/language/lambda#Lambda_capture\">cppreference.com</a> for a full list of possibilities."
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "645373e5",
-   "metadata": {},
-   "source": [
-    "We are going to take a look at three examples from <a href=\"https://www.grimm-jaud.de/index.php/modernes-c-in-der-praxis-linux-magazin-a\">Modernes C++ in der Praxis</a> by Rainer Grimm."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 14,
-   "id": "3514f84c",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "#include <iostream>\n",
-    "\n",
-    "int main() {\n",
-    "\n",
-    "  std::cout << std::endl;\n",
-    "\n",
-    "  std::string copy = \"original\";\n",
-    "  std::string ref  = \"original\";\n",
-    "\n",
-    "  auto lambda = [copy,&ref] { std::cout << copy << \" \" << ref << std::endl; };\n",
-    "\n",
-    "  lambda();\n",
-    "\n",
-    "  copy = \"changed\";\n",
-    "  ref  = \"changed\";\n",
-    "\n",
-    "  lambda();\n",
-    "}"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 15,
-   "id": "7bca56ac",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "\n",
-      "original original\n",
-      "original changed\n"
-     ]
-    }
-   ],
-   "source": [
-    "main();"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "b237f560",
-   "metadata": {},
-   "source": [
-    "In line #10 we have our lambda expression.\n",
-    "- It does not receive arguments through its interface. Thus, we can omit the `( )` part.\n",
-    "- When we want to re-use a lambda we can store it in a variable. For this we need to use `auto`.\n",
-    "- Note the difference in the output between the two invocations of `lambda()`. As we captured `copy` by copy its value inside `lambda()` is not affected by its change in the surrounding scope, while that of `ref` is. The latter was captured by reference."
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "ac5c13c5",
-   "metadata": {},
-   "source": [
-    "***\n",
-    "Small detour: Coming back to what the type is. Let's try to figure out using `typeid`:"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 34,
-   "id": "f0fd0543",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "5.0 is of type d\n",
-      "type of a is i\n",
-      "What is lambda? ZN12__cling_N52216__cling_Un1Qu318EPvE3$_6\n"
-     ]
-    }
-   ],
-   "source": [
-    "std::cout << \"5.0 is of type \" << typeid(5.0).name() << std::endl;\n",
-    "int a;\n",
-    "std::cout << \"type of a is \" << typeid(a).name() << std::endl;\n",
-    "\n",
-    "\n",
-    "auto lambda = [] (int a) { std::cout << a << std::endl; };\n",
-    "std::cout << \"What is lambda? \" << typeid(lambda).name() << std::endl;"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "3393bdde",
-   "metadata": {},
-   "source": [
-    "Not very helpful, hugh. So maybe let's try something else"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 18,
-   "id": "a32b1635",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Writing lambda.cpp\n"
-     ]
-    }
-   ],
-   "source": [
-    "%%file lambda.cpp\n",
-    "\n",
-    "void test() {\n",
-    "\n",
-    "auto lambda = [] (int &a) { a++; };\n",
-    "\n",
-    "int b = 1;\n",
-    "lambda(b); // avoid optimizing out\n",
-    "}"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 19,
-   "id": "85373b9f",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "!g++ -c lambda.cpp"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 20,
-   "id": "fa038d35",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "                 U _GLOBAL_OFFSET_TABLE_\n",
-      "                 U __stack_chk_fail\n",
-      "000000000000001e T test()\n",
-      "0000000000000000 t test()::{lambda(int&)#1}::operator()(int&) const\n"
-     ]
-    }
-   ],
-   "source": [
-    "!nm -C lambda.o"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "ab79093e",
-   "metadata": {},
-   "source": [
-    "Okay, so that really looks very specific. Indeed **\"the type of a closure cannot be named\"** (at least not explicitely), but it can be detected by **`auto`**."
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "d65d40b3",
-   "metadata": {},
-   "source": [
-    "***\n",
-    "Another example from *Modernes C++ in der Praxis*. Here we implement a join method for strings."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 21,
-   "id": "03a872a9",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Writing join.cpp\n"
-     ]
-    }
-   ],
-   "source": [
-    "%%file join.cpp\n",
-    "\n",
-    "#include <iostream>\n",
-    "#include <algorithm>\n",
-    "#include <string>\n",
-    "#include <vector>\n",
-    "\n",
-    "std::string join( std::vector< std::string >& str, std::string sep = \" \" ) {\n",
-    "\n",
-    "  std::string joinStr = \"\";\n",
-    "\n",
-    "  // small mod from original\n",
-    "  // if( not str.size() ) return joinStr;\n",
-    "  if( str.size() == 0 ) return joinStr;\n",
-    "\n",
-    "  std::for_each( str.begin(), str.end()-1,\n",
-    "                 [ &joinStr, sep ] (std::string v) { joinStr += v + sep; } );\n",
-    "\n",
-    "  joinStr += str.back(); // back() returns reference to last entry\n",
-    "  return joinStr;\n",
-    "}\n",
-    "\n",
-    "int main() {\n",
-    "\n",
-    "  std::vector< std::string > myVec;\n",
-    "  std::cout << join( myVec ) << std::endl;\n",
-    "\n",
-    "  myVec.push_back( \"One\" );\n",
-    "  std::cout << join( myVec ) << std::endl;\n",
-    "\n",
-    "  myVec.push_back( \"Two\" );\n",
-    "  std::cout << join( myVec ) << std::endl;\n",
-    "\n",
-    "  myVec.push_back( \"Three\" );\n",
-    "  std::cout << join( myVec, \":\" ) << std::endl;\n",
-    "\n",
-    "  myVec.push_back( \"Four\" );\n",
-    "  std::cout << join( myVec, \"/\" ) << std::endl;\n",
-    "\n",
-    "  myVec.push_back( \"Five\" );\n",
-    "  std::cout << join( myVec, \"XXX\" ) << std::endl;\n",
-    "\n",
-    "  std::cout << std::endl;\n",
-    "}"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 22,
-   "id": "933de670",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "!g++ -Wall -Wextra join.cpp"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 23,
-   "id": "c485b43f",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "\n",
-      "One\n",
-      "One Two\n",
-      "One:Two:Three\n",
-      "One/Two/Three/Four\n",
-      "OneXXXTwoXXXThreeXXXFourXXXFive\n",
-      "\n"
-     ]
-    }
-   ],
-   "source": [
-    "!./a.out"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "f839546e",
-   "metadata": {},
-   "source": [
-    "Final example from Modernes C++ in der Praxis. Here we implement a flexible filter to operate on a vector of random numbers."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 35,
-   "id": "dcaec377",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Overwriting filter.cpp\n"
-     ]
-    }
-   ],
-   "source": [
-    "%%file filter.cpp\n",
-    "\n",
-    "#include <algorithm>\n",
-    "#include <functional>\n",
-    "#include <iostream>\n",
-    "#include <random>\n",
-    "\n",
-    "// This is going to be our filter\n",
-    "std::function< bool(int) > inRange( int low, int up ) {\n",
-    "  return [low,up] ( int d ) { return d >= low && d <= up; };\n",
-    "}\n",
-    "\n",
-    "\n",
-    "int main() {\n",
-    "\n",
-    "  std::cout << std::boolalpha << std::endl;\n",
-    "\n",
-    "  std::cout << \"4 inRange(5,10): \" << inRange(5,10)(4) << std::endl;\n",
-    "\n",
-    "  auto filt = inRange(5,10);\n",
-    "\n",
-    "  std::cout << \"5 inRange(5,10): \" << filt(5) << std::endl;\n",
-    "\n",
-    "  std::cout << std::endl;\n",
-    "\n",
-    "  const int NUM = 60;\n",
-    "\n",
-    "  std::random_device seed;\n",
-    "  std::mt19937 engine( seed() ); // a mersenne twister\n",
-    "\n",
-    "  // distribution\n",
-    "  std::uniform_int_distribution< int > six(1,6);\n",
-    "\n",
-    "  std::vector< int > dice;\n",
-    "  for( int i = 1; i <= NUM; ++i ) dice.push_back( six( engine ) );\n",
-    "\n",
-    "  std::cout << std::count_if( dice.begin(), dice.end(), inRange(6,6) )\n",
-    "    << \" of \" << NUM << \" inRange(6,6)\" << std::endl;\n",
-    "\n",
-    "  std::cout << std::count_if( dice.begin(), dice.end(), inRange(4,6) )\n",
-    "    << \" of \" << NUM << \" inRange(4,6)\" << std::endl;\n",
-    "\n",
-    "  // remove all elements for 1 to 4\n",
-    "  dice.erase( std::remove_if( dice.begin(), dice.end(), inRange(1,4) ),\n",
-    "              dice.end() );\n",
-    "\n",
-    "  // remove_if returns a past-the-end iterator for the new end of the range.\n",
-    "\n",
-    "  std::cout << \"All numbers 5 and 6: \";\n",
-    "  for( auto v: dice ) std::cout << v << \" \";\n",
-    "\n",
-    "  std::cout << \"\\n\\n\";\n",
-    "}"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 25,
-   "id": "b45b0e4f",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "!g++ -Wall -Wextra filter.cpp"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 28,
-   "id": "f85b1bc8",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "\n",
-      "4 inRange(5,10): false\n",
-      "5 inRange(5,10): true\n",
-      "\n",
-      "7 of 60 inRange(6,6)\n",
-      "30 of 60 inRange(4,6)\n",
-      "All numbers 5 and 6: 5 5 6 5 6 5 6 5 6 5 5 6 6 6 5 5 \n",
-      "\n"
-     ]
-    }
-   ],
-   "source": [
-    "!./a.out"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "0ac98da0",
-   "metadata": {},
-   "source": [
-    "***\n",
-    "We had seen that we can store a lambda expression as an object (of some implicit type). However, we can also convert it into a\n",
-    "- function pointer\n",
-    "- std::function\n",
-    "\n",
-    "The last one is what we implicitely did in the filter (generator function) `inRange()` in the previous example."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 30,
-   "id": "cf33e115",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Writing convert.cpp\n"
-     ]
-    }
-   ],
-   "source": [
-    "%%file convert.cpp\n",
-    "\n",
-    "#include <iostream>\n",
-    "#include <functional>\n",
-    "\n",
-    "int main() {\n",
-    "\n",
-    "  using fType = int (*) (int);\n",
-    "\n",
-    "  using sType = std::function< int(int) >;\n",
-    "\n",
-    "  auto impl = [] (int a) { return a+1; };\n",
-    "\n",
-    "  std::cout << \" 1 + 1 = \" << impl( 1 ) << std::endl;\n",
-    "\n",
-    "  fType expl1 = impl;\n",
-    "  std::cout << \" 2 + 1 = \" << expl1( 2 ) << std::endl;\n",
-    "\n",
-    "  sType expl2 = impl;\n",
-    "  std::cout << \" 3 + 1 = \" << expl2( 3 ) << std::endl;\n",
-    "\n",
-    "  std::cout << \"Type of impl is function pointer? \" \n",
-    "            << std::boolalpha\n",
-    "            << std::is_same< fType, decltype( impl ) >::value\n",
-    "            << std::endl;\n",
-    "\n",
-    "  std::cout << \"Type of expl1 is function pointer? \" \n",
-    "            << std::is_same< fType, decltype( expl1 ) >::value\n",
-    "            << std::endl;\n",
-    "\n",
-    "  std::cout << \"Type of expl2 is instance of std::function? \" \n",
-    "            << std::is_same< sType, decltype( expl2 ) >::value\n",
-    "            << std::endl;\n",
-    "}"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 31,
-   "id": "3fbad575",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "!g++ convert.cpp"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 32,
-   "id": "0584e221",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      " 1 + 1 = 2\n",
-      " 2 + 1 = 3\n",
-      " 3 + 1 = 4\n",
-      "Type of impl is function pointer? false\n",
-      "Type of expl1 is function pointer? true\n",
-      "Type of expl2 is instance of std::function? true\n"
-     ]
-    }
-   ],
-   "source": [
-    "!./a.out"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "b4fc6130",
-   "metadata": {},
-   "source": [
-    "A closer look at line 12 shows that in the lambda expression, we did not explicitely specify a **return type**. In this case it will automatically be determined from the `return` statement.\n",
-    "\n",
-    "When we want or need to explicitely specify the return type, then this must be done via the *trailing-return-type* syntax."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 33,
-   "id": "ae57e2ba",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "10.000000"
-      ]
-     },
-     "execution_count": 33,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "auto lFunc = [] (double a) -> double { return 2.0*a; };\n",
-    "lFunc( 5.0 )"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "e04b7032",
-   "metadata": {},
-   "source": [
-    "***\n",
-    "In <a href=\"https://i10git.cs.fau.de/hyteg/hyteg\">HyTeG</a> we often make use of lambdas. Especially for initialising functions and setting boundary conditions. Like in this snippet:   \n",
-    "```c++\n",
-    "real_t k = 2.0;\n",
-    "real_t m = 5.0;\n",
-    "\n",
-    "std::function< real_t(const Point3D&) > solFunc =\n",
-    "  [k, m](const Point3D& x) { sin( k * pi * x[0] ) * sin( m * pi * x[1]; };\n",
-    "\n",
-    "P1Function< real_t > uExact( \"u_analytic\", storage, maxLevel, maxLevel );\n",
-    "uExact.interpolate( solFunc, maxLevel );\n",
-    "```"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "f5d8241e",
-   "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
-}
+{"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":"# Functors, Lambdas and std::function","metadata":{},"id":"789d7a72"},{"cell_type":"markdown","source":"#### Function Pointers\nIn a previous example we had implemented a function two compare to objects of type ```myPair```.","metadata":{},"id":"008aa425"},{"cell_type":"code","source":"class myPair;\nbool cmp( const myPair& left, const myPair& right );","metadata":{},"execution_count":1,"outputs":[],"id":"96f5ab84"},{"cell_type":"markdown","source":"We needed that function to be able to create a set of ```myPair```'s.\n\n        std::set< myPair, decltype( cmp )* > pairs ( cmp );\nWhat we pass to ```std::set```'s constructor is a **function pointer** of type\n\n        bool (*) ( const myPair&, const myPair& )","metadata":{},"id":"ea6fcef6"},{"cell_type":"markdown","source":"***\n- This way to work with functions is something that C++ inherited from C.\n- Not only in the STL, but also in scientific programming we often have the case that we implement something, but want to leave some details to the user:  \n  - Consider e.g. implementing an algorithm to approximate the integral\n$$I = \\int_a^b f(x)\\, dx$$\n  - When we code that we would like to leave the details of the integrand to be specified flexibly by the user.  \n  - As with std::set we can let the user provide a function that we then call inside our code.\n  - This is known as a **callback**.\n- The main downside to using function (pointers) in this approach is that a free function is **stateless**. In order to influence its behaviour we have to pass arguments through its interface. That does not work nicely with the callback idea.\n  - Note: We can add *state* to a function by making some of its local variables ```static```. See the ```accumulate``` examples.\n  - However, a function is a global entity. Thus, there can always only be one state for it.","metadata":{},"id":"dc79e822"},{"cell_type":"markdown","source":"#### Functors\nIn C++ we can as one alternative use a **function object**, a.k.a. **functor**. This is an object of a class that overloads the function call operator ```operator()```.\n\n##### **Example 1:**","metadata":{},"id":"9ce08962"},{"cell_type":"code","source":"#include <iostream>\n\nclass greeter{\npublic:\n  void operator() ( const std::string& str ) {\n    std::cout << \"Greetings \" << str << std::endl;\n  }\n};","metadata":{},"execution_count":2,"outputs":[],"id":"9bf146ec"},{"cell_type":"code","source":"int main() {\n  greeter hello;\n  hello( \"Class\" );\n}","metadata":{},"execution_count":3,"outputs":[],"id":"b13aa200"},{"cell_type":"code","source":"main();","metadata":{},"execution_count":4,"outputs":[{"name":"stdout","output_type":"stream","text":"Greetings Class\n"}],"id":"f7a3701a"},{"cell_type":"markdown","source":"***\nNow that was a simple functor and did only demonstrate **how** it works and not **why** that approach can be advantageous.\n\n##### **Example 2:**  \nIn our second example we will use a stateful functor that allows to perform different binary operations. The type of operation will be passed via its constructor.","metadata":{},"id":"58a187c4"},{"cell_type":"code","source":"#include <iostream>\n\nclass BinaryOperator {\n\npublic:\n\n  typedef enum { ADD, MULT } type;\n\n  BinaryOperator() = delete;\n  BinaryOperator( BinaryOperator::type op ) : whatToDo( op ) {};\n\n  int operator() ( int a, int b ) {\n    switch( whatToDo ) {\n    case ADD:\n      return a+b;\n    case MULT:\n      return a*b;\n    }\n  }\n\nprivate:\n  type whatToDo;\n\n};","metadata":{},"execution_count":5,"outputs":[],"id":"8c0f30c5"},{"cell_type":"code","source":"int main() {\n\n  int a = 2;\n  int b = 3;\n\n  BinaryOperator adder( BinaryOperator::ADD );\n  BinaryOperator multiplier( BinaryOperator::MULT );\n\n  std::cout << adder( a, b ) << std::endl;\n  std::cout << multiplier( a, b ) << std::endl;\n}","metadata":{},"execution_count":6,"outputs":[],"id":"05517c3a-eb4b-4827-9f74-54abf0264cca"},{"cell_type":"code","source":"main();","metadata":{},"execution_count":7,"outputs":[{"name":"stdout","output_type":"stream","text":"5\n6\n"}],"id":"2777a5a1-f8bc-4907-90e2-488967071529"},{"cell_type":"markdown","source":"##### **Example 3:**  \nSo how would our set example for myPair look like with a functor?","metadata":{},"id":"6adaab27"},{"cell_type":"code","source":"%%file functor.cpp\n\n#include <iostream>\n#include <set>\n\nstruct myPair {\n  myPair( int fir, int sec ) : fir_( fir ), sec_( sec ) {\n    std::cout << \"(\" << fir_ << \",\" << sec_ << \") constructed\" << std::endl;\n  };\n  int fir_;\n  int sec_;\n};\n\nstruct myCompare {\n  bool operator() ( const myPair& left, const myPair& right ) const {\n    int val1 = left.fir_ * left.fir_ + left.sec_ * left.sec_;\n    int val2 = right.fir_ * right.fir_ + right.sec_ * right.sec_;\n    return val1 < val2;\n  }\n};\n\nint main() {\n\n  myCompare cmp;\n  std::set< myPair, myCompare > pairs( cmp );\n\n  myPair p1( 1, 2 );\n  myPair p2( 3, 4 );\n\n  std::cout << std::boolalpha;\n  std::cout << \"p1 < p2 is \" << cmp( p1, p2 ) << std::endl;\n  std::cout << \"p2 < p1 is \" << cmp( p2, p1 ) << std::endl;\n\n  pairs.insert( p1 );\n  pairs.insert( p2 );\n\n  pairs.emplace( 3, 4 );\n  pairs.emplace( 5, 6 );\n}","metadata":{},"execution_count":8,"outputs":[{"name":"stdout","output_type":"stream","text":"Overwriting functor.cpp\n"}],"id":"856ee747"},{"cell_type":"code","source":"!g++ -Wall -Wextra functor.cpp","metadata":{},"execution_count":9,"outputs":[],"id":"4adb7f0b"},{"cell_type":"code","source":"!./a.out","metadata":{},"execution_count":10,"outputs":[{"name":"stdout","output_type":"stream","text":"(1,2) constructed\n(3,4) constructed\np1 < p2 is true\np2 < p1 is false\n(3,4) constructed\n(5,6) constructed\n"}],"id":"f9bfde7f"},{"cell_type":"markdown","source":"#### std::function\n\nQuoting from cppreference:\n> Class template std::function is a general-purpose polymorphic function wrapper. Instances of std::function can store, copy, and invoke any CopyConstructible Callable target -- functions, lambda expressions, bind expressions, or other function objects, as well as pointers to member functions and pointers to data members.\n>\n> The stored callable object is called the target of std::function. If a std::function contains no target, it is called empty. Invoking the target of an empty std::function results in std::bad_function_call exception being thrown. \n\nThe functionality of ```std::function``` is quite useful especially in combination with lambda functions (see below).","metadata":{},"id":"c51deb94-f9c2-4a88-914b-ddf70f29601e"},{"cell_type":"markdown","source":"##### **Example 4:**\nAssign a simple free-function","metadata":{},"id":"6c584ecb-10c3-4ff2-ab53-2a66c0963009"},{"cell_type":"code","source":"#include <iostream>\nvoid sayIt() { std::cout << \"He said captain, I said wot\" << std::endl; }","metadata":{},"execution_count":1,"outputs":[],"id":"21120bbb-03a7-4048-97f4-0426c40c5bac"},{"cell_type":"code","source":"// generate an object of type std::function;\n\n// need this header file\n#include <functional>\n\n// need to supply the prototype of the function/invocation that we want to target\nstd::function< void( ) > sensible;","metadata":{},"execution_count":2,"outputs":[],"id":"bab0ab95-e5fd-4368-b3c2-77bcb869cfe0"},{"cell_type":"code","source":"// std::function overloads 'operator bool' so we can check if anything is targetted, yet\nif( !sensible ) {\n    std::cout << \"empty -> nothing to do!\" << std::endl;\n}","metadata":{},"execution_count":3,"outputs":[{"name":"stdout","output_type":"stream","text":"empty -> nothing to do!\n"}],"id":"b4e3f68a-6c70-49e7-a04c-924804c4cb35"},{"cell_type":"code","source":"// now assign a target to our std::object\nsensible = sayIt;\n\n// and perform the invocation\nsensible();","metadata":{},"execution_count":5,"outputs":[{"name":"stdout","output_type":"stream","text":"He said captain, I said wot\n"}],"id":"c5b3e4d0-64b4-47c6-848f-f787bf9c0b17"},{"cell_type":"markdown","source":"##### **Example 5:**\nNow let us use a functor with a slightly more complicated interface","metadata":{},"id":"1ad030ff-9527-4436-be80-72baf9ac7b29"},{"cell_type":"code","source":"// that's our functor\nstruct Mult {\n    int operator() ( int a, int b ) { return a*b; } \n}","metadata":{},"execution_count":6,"outputs":[],"id":"ff8d558b-da83-46d9-9842-8e0d9d5ba56d"},{"cell_type":"code","source":"// if we want, we can alias our std::function type\nusing binaryOp = std::function< int(int,int) >;\n\n// now instantiate an object that targets the functor\nbinaryOp multiply = Mult();\n\n// note that we needed the () to differentiate between the invocation and the functor itself!\n\nmultiply(2,3)","metadata":{},"execution_count":7,"outputs":[{"execution_count":7,"output_type":"execute_result","data":{"text/plain":"6"},"metadata":{}}],"id":"b5790b96-bf62-4d6e-ad9c-e56839882728"},{"cell_type":"markdown","source":"##### **Example 6:**\nA member function of a class can also serve as target","metadata":{},"id":"589b7083-7a36-4ff8-bdd0-c46f9994228c"},{"cell_type":"code","source":"struct ItemsInStore{\n    int num;\n    ItemsInStore() = delete;\n    ItemsInStore( int num ) : num(num) {};\n    void decrementAndShowRest() {\n        std::cout << \"Only \" << --num << \" items left!\" << std::endl;\n    }\n};","metadata":{},"execution_count":9,"outputs":[],"id":"646b302f-cdf5-40ed-98f8-01d98a9b277a"},{"cell_type":"code","source":"std::function< void( ItemsInStore& ) > takeOne = &ItemsInStore::decrementAndShowRest;","metadata":{},"execution_count":10,"outputs":[],"id":"b56b370a-654f-4665-a86d-1b4a1497a813"},{"cell_type":"code","source":"ItemsInStore candyBox( 5 );\ntakeOne( candyBox );\ntakeOne( candyBox );","metadata":{},"execution_count":11,"outputs":[{"name":"stdout","output_type":"stream","text":"Only 4 items left!\nOnly 3 items left!\n"}],"id":"b267e62f"},{"cell_type":"markdown","source":"#### Lambdas\nUsing *function pointers* or *functors* implies some significant coding overhead.\n\nC++11 introduced **lambda (functions)**, also known as **closures**, as a leight-weight alternative, that can be written inline in the source code.","metadata":{},"id":"9d2c9715"},{"cell_type":"markdown","source":"Let's start with an example","metadata":{},"id":"41bbe5a3"},{"cell_type":"code","source":"#include <vector>\n#include <iostream>\n#include <algorithm>\n\nstd::vector< int > numbers{1,2,3,4,5};\n\nfor_each( numbers.begin(), numbers.end(), []( int& n ) { n *= n; } );\n\nfor( int v: numbers ) std::cout << \" \" << v;","metadata":{},"execution_count":13,"outputs":[{"name":"stdout","output_type":"stream","text":" 1 4 9 16 25"}],"id":"24ad0ef1"},{"cell_type":"markdown","source":"The expression **`[]( int& n ) { n *= n; }`** is an *anonymous function*, so called, lambda, lambda expression, lambda function or closure.\n\n- The `(...)` part specifies the interface.\n- If a lambda function does not return a value we can omit the return type.\n- The `{...}` part is for the body of the function.\n- The `[...]` part allows to *capture* variables from the current scope.\n\nlambda functions do not really provide extra functionality. We could accomplish the same with a free-function or a functor. In this sense they are only syntactic sugar, \"but of the sweetest kind\" (Rainer Grimm).","metadata":{},"id":"ff3d112c"},{"cell_type":"markdown","source":"##### Captures:\n\nThe `[ ]` part of the lambda expression can contain a comma-separated list of stuff we want to *capture*. This allows using it inside the body of the lambda without explicitely passing it through the interface. There are also two *defaults* we can speficy:\n\n|       | effect |\n|:-----:|:-------|\n| &     | implicitly capture the used automatic variables by reference |\n| :     | implicitly capture the used automatic variables by copy      |\n| a     | capture a from surrounding scope by copy                     |\n| &a    | capture a from surrounding scope by reference                |\n\nSee e.g. <a href=\"https://en.cppreference.com/w/cpp/language/lambda#Lambda_capture\">cppreference.com</a> for a full list of possibilities.","metadata":{},"id":"5764a9c9"},{"cell_type":"markdown","source":"We are going to take a look at three examples from <a href=\"https://www.grimm-jaud.de/index.php/modernes-c-in-der-praxis-linux-magazin-a\">Modernes C++ in der Praxis</a> by Rainer Grimm.","metadata":{},"id":"645373e5"},{"cell_type":"code","source":"#include <iostream>\n\nint main() {\n\n  std::cout << std::endl;\n\n  std::string copy = \"original\";\n  std::string ref  = \"original\";\n\n  auto lambda = [copy,&ref] { std::cout << copy << \" \" << ref << std::endl; };\n\n  lambda();\n\n  copy = \"changed\";\n  ref  = \"changed\";\n\n  lambda();\n}","metadata":{},"execution_count":14,"outputs":[],"id":"3514f84c"},{"cell_type":"code","source":"main();","metadata":{},"execution_count":15,"outputs":[{"name":"stdout","output_type":"stream","text":"\noriginal original\noriginal changed\n"}],"id":"7bca56ac"},{"cell_type":"markdown","source":"In line #10 we have our lambda expression.\n- It does not receive arguments through its interface. Thus, we can omit the `( )` part.\n- When we want to re-use a lambda we can store it in a variable. For this we need to use `auto`.\n- Note the difference in the output between the two invocations of `lambda()`. As we captured `copy` by copy its value inside `lambda()` is not affected by its change in the surrounding scope, while that of `ref` is. The latter was captured by reference.","metadata":{},"id":"b237f560"},{"cell_type":"markdown","source":"***\nSmall detour: Coming back to what the type is. Let's try to figure out using `typeid`:","metadata":{},"id":"ac5c13c5"},{"cell_type":"code","source":"std::cout << \"5.0 is of type \" << typeid(5.0).name() << std::endl;\nint a;\nstd::cout << \"type of a is \" << typeid(a).name() << std::endl;\n\n\nauto lambda = [] (int a) { std::cout << a << std::endl; };\nstd::cout << \"What is lambda? \" << typeid(lambda).name() << std::endl;","metadata":{},"execution_count":34,"outputs":[{"name":"stdout","output_type":"stream","text":"5.0 is of type d\ntype of a is i\nWhat is lambda? ZN12__cling_N52216__cling_Un1Qu318EPvE3$_6\n"}],"id":"f0fd0543"},{"cell_type":"markdown","source":"Not very helpful, hugh. So maybe let's try something else","metadata":{},"id":"3393bdde"},{"cell_type":"code","source":"%%file lambda.cpp\n\nvoid test() {\n\nauto lambda = [] (int &a) { a++; };\n\nint b = 1;\nlambda(b); // avoid optimizing out\n}","metadata":{},"execution_count":18,"outputs":[{"name":"stdout","output_type":"stream","text":"Writing lambda.cpp\n"}],"id":"a32b1635"},{"cell_type":"code","source":"!g++ -c lambda.cpp","metadata":{},"execution_count":19,"outputs":[],"id":"85373b9f"},{"cell_type":"code","source":"!nm -C lambda.o","metadata":{},"execution_count":20,"outputs":[{"name":"stdout","output_type":"stream","text":"                 U _GLOBAL_OFFSET_TABLE_\n                 U __stack_chk_fail\n000000000000001e T test()\n0000000000000000 t test()::{lambda(int&)#1}::operator()(int&) const\n"}],"id":"fa038d35"},{"cell_type":"markdown","source":"Okay, so that really looks very specific. Indeed **\"the type of a closure cannot be named\"** (at least not explicitely), but it can be detected by **`auto`**.","metadata":{},"id":"ab79093e"},{"cell_type":"markdown","source":"***\nAnother example from *Modernes C++ in der Praxis*. Here we implement a join method for strings.","metadata":{},"id":"d65d40b3"},{"cell_type":"code","source":"%%file join.cpp\n\n#include <iostream>\n#include <algorithm>\n#include <string>\n#include <vector>\n\nstd::string join( std::vector< std::string >& str, std::string sep = \" \" ) {\n\n  std::string joinStr = \"\";\n\n  // small mod from original\n  // if( not str.size() ) return joinStr;\n  if( str.size() == 0 ) return joinStr;\n\n  std::for_each( str.begin(), str.end()-1,\n                 [ &joinStr, sep ] (std::string v) { joinStr += v + sep; } );\n\n  joinStr += str.back(); // back() returns reference to last entry\n  return joinStr;\n}\n\nint main() {\n\n  std::vector< std::string > myVec;\n  std::cout << join( myVec ) << std::endl;\n\n  myVec.push_back( \"One\" );\n  std::cout << join( myVec ) << std::endl;\n\n  myVec.push_back( \"Two\" );\n  std::cout << join( myVec ) << std::endl;\n\n  myVec.push_back( \"Three\" );\n  std::cout << join( myVec, \":\" ) << std::endl;\n\n  myVec.push_back( \"Four\" );\n  std::cout << join( myVec, \"/\" ) << std::endl;\n\n  myVec.push_back( \"Five\" );\n  std::cout << join( myVec, \"XXX\" ) << std::endl;\n\n  std::cout << std::endl;\n}","metadata":{},"execution_count":21,"outputs":[{"name":"stdout","output_type":"stream","text":"Writing join.cpp\n"}],"id":"03a872a9"},{"cell_type":"code","source":"!g++ -Wall -Wextra join.cpp","metadata":{},"execution_count":22,"outputs":[],"id":"933de670"},{"cell_type":"code","source":"!./a.out","metadata":{},"execution_count":23,"outputs":[{"name":"stdout","output_type":"stream","text":"\nOne\nOne Two\nOne:Two:Three\nOne/Two/Three/Four\nOneXXXTwoXXXThreeXXXFourXXXFive\n\n"}],"id":"c485b43f"},{"cell_type":"markdown","source":"Final example from Modernes C++ in der Praxis. Here we implement a flexible filter to operate on a vector of random numbers.","metadata":{},"id":"f839546e"},{"cell_type":"code","source":"%%file filter.cpp\n\n#include <algorithm>\n#include <functional>\n#include <iostream>\n#include <random>\n\n// This is going to be our filter\nstd::function< bool(int) > inRange( int low, int up ) {\n  return [low,up] ( int d ) { return d >= low && d <= up; };\n}\n\n\nint main() {\n\n  std::cout << std::boolalpha << std::endl;\n\n  std::cout << \"4 inRange(5,10): \" << inRange(5,10)(4) << std::endl;\n\n  auto filt = inRange(5,10);\n\n  std::cout << \"5 inRange(5,10): \" << filt(5) << std::endl;\n\n  std::cout << std::endl;\n\n  const int NUM = 60;\n\n  std::random_device seed;\n  std::mt19937 engine( seed() ); // a mersenne twister\n\n  // distribution\n  std::uniform_int_distribution< int > six(1,6);\n\n  std::vector< int > dice;\n  for( int i = 1; i <= NUM; ++i ) dice.push_back( six( engine ) );\n\n  std::cout << std::count_if( dice.begin(), dice.end(), inRange(6,6) )\n    << \" of \" << NUM << \" inRange(6,6)\" << std::endl;\n\n  std::cout << std::count_if( dice.begin(), dice.end(), inRange(4,6) )\n    << \" of \" << NUM << \" inRange(4,6)\" << std::endl;\n\n  // remove all elements for 1 to 4\n  dice.erase( std::remove_if( dice.begin(), dice.end(), inRange(1,4) ),\n              dice.end() );\n\n  // remove_if returns a past-the-end iterator for the new end of the range.\n\n  std::cout << \"All numbers 5 and 6: \";\n  for( auto v: dice ) std::cout << v << \" \";\n\n  std::cout << \"\\n\\n\";\n}","metadata":{},"execution_count":35,"outputs":[{"name":"stdout","output_type":"stream","text":"Overwriting filter.cpp\n"}],"id":"dcaec377"},{"cell_type":"code","source":"!g++ -Wall -Wextra filter.cpp","metadata":{},"execution_count":25,"outputs":[],"id":"b45b0e4f"},{"cell_type":"code","source":"!./a.out","metadata":{},"execution_count":28,"outputs":[{"name":"stdout","output_type":"stream","text":"\n4 inRange(5,10): false\n5 inRange(5,10): true\n\n7 of 60 inRange(6,6)\n30 of 60 inRange(4,6)\nAll numbers 5 and 6: 5 5 6 5 6 5 6 5 6 5 5 6 6 6 5 5 \n\n"}],"id":"f85b1bc8"},{"cell_type":"markdown","source":"***\nWe had seen that we can store a lambda expression as an object (of some implicit type). However, we can also convert it into a\n- function pointer\n- std::function\n\nThe last one is what we implicitely did in the filter (generator function) `inRange()` in the previous example.","metadata":{},"id":"0ac98da0"},{"cell_type":"code","source":"%%file convert.cpp\n\n#include <iostream>\n#include <functional>\n\nint main() {\n\n  using fType = int (*) (int);\n\n  using sType = std::function< int(int) >;\n\n  auto impl = [] (int a) { return a+1; };\n\n  std::cout << \" 1 + 1 = \" << impl( 1 ) << std::endl;\n\n  fType expl1 = impl;\n  std::cout << \" 2 + 1 = \" << expl1( 2 ) << std::endl;\n\n  sType expl2 = impl;\n  std::cout << \" 3 + 1 = \" << expl2( 3 ) << std::endl;\n\n  std::cout << \"Type of impl is function pointer? \" \n            << std::boolalpha\n            << std::is_same< fType, decltype( impl ) >::value\n            << std::endl;\n\n  std::cout << \"Type of expl1 is function pointer? \" \n            << std::is_same< fType, decltype( expl1 ) >::value\n            << std::endl;\n\n  std::cout << \"Type of expl2 is instance of std::function? \" \n            << std::is_same< sType, decltype( expl2 ) >::value\n            << std::endl;\n}","metadata":{},"execution_count":30,"outputs":[{"name":"stdout","output_type":"stream","text":"Writing convert.cpp\n"}],"id":"cf33e115"},{"cell_type":"code","source":"!g++ convert.cpp","metadata":{},"execution_count":31,"outputs":[],"id":"3fbad575"},{"cell_type":"code","source":"!./a.out","metadata":{},"execution_count":32,"outputs":[{"name":"stdout","output_type":"stream","text":" 1 + 1 = 2\n 2 + 1 = 3\n 3 + 1 = 4\nType of impl is function pointer? false\nType of expl1 is function pointer? true\nType of expl2 is instance of std::function? true\n"}],"id":"0584e221"},{"cell_type":"markdown","source":"A closer look at line 12 shows that in the lambda expression, we did not explicitely specify a **return type**. In this case it will automatically be determined from the `return` statement.\n\nWhen we want or need to explicitely specify the return type, then this must be done via the *trailing-return-type* syntax.","metadata":{},"id":"b4fc6130"},{"cell_type":"code","source":"auto lFunc = [] (double a) -> double { return 2.0*a; };\nlFunc( 5.0 )","metadata":{},"execution_count":33,"outputs":[{"execution_count":33,"output_type":"execute_result","data":{"text/plain":"10.000000"},"metadata":{}}],"id":"ae57e2ba"},{"cell_type":"markdown","source":"***\nIn <a href=\"https://i10git.cs.fau.de/hyteg/hyteg\">HyTeG</a> we often make use of lambdas. Especially for initialising functions and setting boundary conditions. Like in this snippet:   \n```c++\nreal_t k = 2.0;\nreal_t m = 5.0;\n\nstd::function< real_t(const Point3D&) > solFunc =\n  [k, m](const Point3D& x) { sin( k * pi * x[0] ) * sin( m * pi * x[1]; };\n\nP1Function< real_t > uExact( \"u_analytic\", storage, maxLevel, maxLevel );\nuExact.interpolate( solFunc, maxLevel );\n```","metadata":{},"id":"e04b7032"},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[],"id":"f5d8241e"}]}
\ No newline at end of file
diff --git a/notebooks/10_Polymorphic_Classes.ipynb b/notebooks/10_Polymorphic_Classes.ipynb
index 9cd604421edd7d7403de0c1615cbbb0a73aa9cfe..c8b24b3cf8b4c0a36832b6869be1c2a2ce98c6ce 100644
--- a/notebooks/10_Polymorphic_Classes.ipynb
+++ b/notebooks/10_Polymorphic_Classes.ipynb
@@ -1,618 +1 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "id": "1a6233be",
-   "metadata": {},
-   "source": [
-    "# Polymorphic or Virtual Classes"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "7ec80016",
-   "metadata": {},
-   "source": [
-    "We return to our example from <a href=\"https://www.hanser-kundencenter.de/fachbuch/artikel/9783446458468\">[Go19]</a> and extend it a little."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 1,
-   "id": "7942848b",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "#include <iostream>\n",
-    "\n",
-    "class person {\n",
-    "\n",
-    "public:\n",
-    "  person( const std::string& name ) : name(name) {};\n",
-    "\n",
-    "  void all_info() const {\n",
-    "    std::cout << \"[person]   My name is \" << name << std::endl;\n",
-    "  }\n",
-    "\n",
-    "protected:\n",
-    "  std::string name;\n",
-    "};"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 2,
-   "id": "f40024e2",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "class student : public person {\n",
-    "\n",
-    "public:\n",
-    "  student( const std::string& name, const std::string program ) :\n",
-    "    person(name), program(program) {}\n",
-    "\n",
-    "  void all_info() const {\n",
-    "    std::cout << \"[student]  My name is \" << name\n",
-    "              << \", I study \" << program << std::endl;\n",
-    "  }\n",
-    "\n",
-    "private:\n",
-    "  std::string program;\n",
-    "};"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 3,
-   "id": "459a1ce0",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "class researcher : public person {\n",
-    "\n",
-    "public:\n",
-    "  researcher( const std::string& name, const std::string& field ) :\n",
-    "    person(name), field(field) {}\n",
-    "\n",
-    "  void all_info() const {\n",
-    "    std::cout << \"[researcher]  My name is \" << name\n",
-    "              << \", I work on problems in \" << field << std::endl;\n",
-    "  }\n",
-    "\n",
-    "private:\n",
-    "  std::string field;\n",
-    "};"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "c5c9fb7a",
-   "metadata": {},
-   "source": [
-    "As `student`s and `researcher`s are `person`s we can e.g. generated a vector of person pointers, where each pointer targets a different university member."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 4,
-   "id": "5ff4684f",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "#include <vector>\n",
-    "\n",
-    "student joe( \"Joe\", \"Geophysics\" );\n",
-    "student jane( \"Jane\", \"Geology\" );\n",
-    "\n",
-    "researcher erika( \"Erika\", \"Seismology\" );\n",
-    "person franz( \"Franz\" );\n",
-    "\n",
-    "std::vector<person*> uniMembers;\n",
-    "\n",
-    "uniMembers.push_back( &joe );\n",
-    "uniMembers.push_back( &jane );\n",
-    "uniMembers.push_back( &erika );\n",
-    "uniMembers.push_back( &franz );"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "56cad921",
-   "metadata": {},
-   "source": [
-    "* Because of inheritance, we can now have all pointers to our different people in the same vector, although the targeted objects are of different type.\n",
-    "* Problem is, when we work with the vectors and ask for info we only get the minimal stuff from the base class"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 5,
-   "id": "aebeaf35",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "[person]   My name is Joe\n",
-      "[person]   My name is Jane\n",
-      "[person]   My name is Erika\n",
-      "[person]   My name is Franz\n"
-     ]
-    }
-   ],
-   "source": [
-    "for( auto memb: uniMembers ) memb->all_info();"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "3f7ae736",
-   "metadata": {},
-   "source": [
-    "Instead of the full records, such as"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 6,
-   "id": "445c4d28",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "[student]  My name is Jane, I study Geology\n",
-      "[researcher]  My name is Erika, I work on problems in Seismology\n"
-     ]
-    }
-   ],
-   "source": [
-    "jane.all_info();\n",
-    "erika.all_info();"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "977efc72",
-   "metadata": {},
-   "source": [
-    "The solution to this is to make our classes **polymorphic**.\n",
-    "\n",
-    "*Definition:*   \n",
-    "A class that contains at least one **virtual function** is called **polymorphic** or **virtual**."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 7,
-   "id": "4b596bd2",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "#include <iostream>\n",
-    "\n",
-    "class person {\n",
-    "\n",
-    "public:\n",
-    "  person( const std::string& name ) : name(name) {};\n",
-    "\n",
-    "  virtual void all_info() const {\n",
-    "    std::cout << \"[person]      My name is \" << name << std::endl;\n",
-    "  }\n",
-    "\n",
-    "protected:\n",
-    "  std::string name;\n",
-    "};\n",
-    "\n",
-    "class student : public person {\n",
-    "\n",
-    "public:\n",
-    "  student( const std::string& name, const std::string program ) :\n",
-    "    person(name), program(program) {}\n",
-    "\n",
-    "  void all_info() const {\n",
-    "    std::cout << \"[student]     My name is \" << name\n",
-    "              << \", I study \" << program << std::endl;\n",
-    "  }\n",
-    "\n",
-    "private:\n",
-    "  std::string program;\n",
-    "};\n",
-    "\n",
-    "class researcher : public person {\n",
-    "\n",
-    "public:\n",
-    "  researcher( const std::string& name, const std::string& field ) :\n",
-    "    person(name), field(field) {}\n",
-    "\n",
-    "  void all_info() const {\n",
-    "    std::cout << \"[researcher]  My name is \" << name\n",
-    "              << \", I work on problems in \" << field << std::endl;\n",
-    "  }\n",
-    "\n",
-    "private:\n",
-    "  std::string field;\n",
-    "};"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 8,
-   "id": "12bebbf9",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "[student]     My name is Joe, I study Geophysics\n",
-      "[student]     My name is Jane, I study Geology\n",
-      "[researcher]  My name is Erika, I work on problems in Seismology\n",
-      "[person]      My name is Franz\n"
-     ]
-    }
-   ],
-   "source": [
-    "#include <vector>\n",
-    "\n",
-    "student joe( \"Joe\", \"Geophysics\" );\n",
-    "student jane( \"Jane\", \"Geology\" );\n",
-    "\n",
-    "researcher erika( \"Erika\", \"Seismology\" );\n",
-    "person franz( \"Franz\" );\n",
-    "\n",
-    "std::vector<person*> uniMembers;\n",
-    "\n",
-    "uniMembers.push_back( &joe );\n",
-    "uniMembers.push_back( &jane );\n",
-    "uniMembers.push_back( &erika );\n",
-    "uniMembers.push_back( &franz );\n",
-    "\n",
-    "for( auto memb: uniMembers ) memb->all_info();"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "ef04a619",
-   "metadata": {},
-   "source": [
-    "**Explanation**  \n",
-    "So what is the difference here? Whenever we work with a **pointer** `pVar` or a **reference** `rVar` to a class and invoke a function `myFunc()` via that on the target the compiler will check the following:\n",
-    "\n",
-    "1. What is the **static type** of `pVal` and or `pVar`, i.e. how were they declared?\n",
-    "1. Does that class have a method `myFunc()`?\n",
-    "1. Is `myFunc()` accessible, i.e. public, or not, i.e. private?\n",
-    "1. Is it a **virtual function**?\n",
-    "   * No: Then invoke it.\n",
-    "   * Yes: Check what the **dynamic type** is of `pVal` and or `pVar`, i.e. the type of the object they target.\n",
-    "   Then invoke `myFunc()` for that type."
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "ae46b4e3",
-   "metadata": {},
-   "source": [
-    "**Remark #1:**  \n",
-    "This only works for pointers and references, but not for variables, even if they are initialised or copy constructed from a child object."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 9,
-   "id": "ccb162c8",
-   "metadata": {
-    "scrolled": true
-   },
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "[person]      My name is Joe\n"
-     ]
-    }
-   ],
-   "source": [
-    "person alias{joe};\n",
-    "alias.all_info();"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "2d6da352",
-   "metadata": {},
-   "source": [
-    "Only the parts of `joe` that belong to its `person` base class are used for the initialisation. This is sometimes refered to as **slicing**."
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "ad22ac97",
-   "metadata": {},
-   "source": [
-    "**Remark #2:**  \n",
-    "The decision which version of `all_info()` must be invoked **cannot** be made by the compiler, as it may not have the necessary information on the type of the target of a pointer or reference. It can only be made at **runtime**."
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "bcb61161",
-   "metadata": {},
-   "source": [
-    "#### Terminology\n",
-    "Since the decision which virtual method is invoked on a pointer or reference to a polymorphic object is performed at runtime, one calls this **late** or **dynamic binding**.\n",
-    "\n",
-    "It constitutes a form of **dynamic polymorphism**, as opposed to the static polymorphism of overloading or templates, which get's resolved at compile-time."
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "370a4417",
-   "metadata": {},
-   "source": [
-    "#### Costs\n",
-    "In order to be able to correctly dispatch the virtual function call at runtime, the compiler generates a **virtual function table** (also **virtual method table**, **vtable**, **dispatch table**). The necessary table lookup constitutes an indirection and increases the costs for the function invokation.\n",
-    "\n",
-    "If your function is short (i.e. does not perform a lot of work) then this extra overhead can be critically significant. If you function is long is will be negligible."
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "e27f36b9",
-   "metadata": {},
-   "source": [
-    "### Overriding"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "960b3f74",
-   "metadata": {},
-   "source": [
-    "In our example all child classes (`student` and `researcher`) have implemented their own version of `all_info()` and, thus, **overridden** the one from the base class. This is, however, not required. If the base class method is not overridden in a child, the base class method will simply be used."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 10,
-   "id": "99352379",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "class staff : public person{\n",
-    "    using person::person;\n",
-    "};"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 17,
-   "id": "454ccaaf",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "[person]      My name is Linda\n"
-     ]
-    }
-   ],
-   "source": [
-    "person* secretary = new staff( \"Linda\" );\n",
-    "secretary->all_info();"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "80e7e3b3",
-   "metadata": {},
-   "source": [
-    "Especially in larger code bases it can be come tedious to not loose the overview on which member functions are virtual and which are not. Or whether we are overriding the correct version of a method."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 5,
-   "id": "bd457522",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "#include <iostream>\n",
-    "\n",
-    "struct A {\n",
-    "    void func1() { std::cout << \"A::func1 is executing\" << std::endl; };\n",
-    "    virtual void func2( double a ) { std::cout << \"func2 from A: a = \" << a << std::endl; }; \n",
-    "};\n",
-    "\n",
-    "\n",
-    "struct B : public A {\n",
-    "    void func1() { std::cout << \"B::func1 is executing\" << std::endl; };\n",
-    "    virtual void func2( int a ) { std::cout << \"func2 from B: a = \" << a << std::endl; };\n",
-    "};"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 6,
-   "id": "4a0a85ba",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "A::func1 is executing\n",
-      "func2 from A: a = 2\n"
-     ]
-    }
-   ],
-   "source": [
-    "A* obj = new B;\n",
-    "obj->func1();\n",
-    "obj->func2( 2 );"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "6414fc0e",
-   "metadata": {},
-   "source": [
-    "`A::func1` is not virtual, so we don't overide and while `A::func2` is virtual, the interface of `B::func2` is different.\n",
-    "\n",
-    "A smart compiler might warn us on the latter:"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 7,
-   "id": "3c824171",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Writing fail.cpp\n"
-     ]
-    }
-   ],
-   "source": [
-    "%%file fail.cpp\n",
-    "\n",
-    "#include <iostream>\n",
-    "\n",
-    "struct A {\n",
-    "  void func1() { std::cout << \"A::func1 is executing\" << std::endl; };\n",
-    "    \n",
-    "  virtual void func2( double a ) { std::cout << \"func2 from A: a = \" << a\n",
-    "                                             << std::endl; }; \n",
-    "};\n",
-    "\n",
-    "\n",
-    "struct B : public A {\n",
-    "  void func1() { std::cout << \"B::func1 is executing\" << std::endl; };\n",
-    "  virtual void func2( int a ) { std::cout << \"func2 from B: a = \" << a\n",
-    "                                          << std::endl; };\n",
-    "};"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 8,
-   "id": "29c729c5",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "fail.cpp:14:16: warning: 'B::func2' hides overloaded virtual function [-Woverloaded-virtual]\n",
-      "  virtual void func2( int a ) { std::cout << \"func2 from B: a = \" << a\n",
-      "               ^\n",
-      "fail.cpp:7:16: note: hidden overloaded virtual function 'A::func2' declared here: type mismatch at 1st parameter ('double' vs 'int')\n",
-      "  virtual void func2( double a ) { std::cout << \"func2 from A: a = \" << a\n",
-      "               ^\n",
-      "1 warning generated.\n"
-     ]
-    }
-   ],
-   "source": [
-    "!clang++ -Wall -Wextra -c fail.cpp"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "6774e9d0",
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  },
-  {
-   "cell_type": "markdown",
-   "id": "413b3e71",
-   "metadata": {},
-   "source": [
-    "### Pure Virtual Functions and Abstract Classes"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "ebb14ead",
-   "metadata": {},
-   "source": [
-    "Consider the following application scenario:\n",
-    "\n",
-    "- We want to implement four specialised matrix classes\n",
-    "  - `DenseMatrix`\n",
-    "  - `DenseSymMatrix`\n",
-    "  - `SparseMatrix`\n",
-    "  - `SparseSymMatrix`\n",
-    "- They all should be children of a common `BaseMatrix` base class.\n",
-    "- All of them should provide a method `multWithVector()` with the same signature.\n",
-    "- We want to be able to invoke that method on a base class pointer or reference.\n",
-    "\n",
-    " This gives rise to the following questions:\n",
-    " 1. How should `BaseMatrix::multWithVector()` be implemented?\n",
-    " 1. Can we enforce that someone who adds another child, say `DenseSkewMatrix` does not forget to implement `DenseSkewMatrix::multWithVector()`?\n",
-    "\n",
-    "A sensible implementation of `BaseMatrix::multWithVector()` will not be possible, as the base class has no knowledge on the details of how its children store their matrices. We could only do an empty implementation or one that e.g. throws an exception. The latter would at least lead to a runtime crash, if we call `multWithVecotr()` on a base class pointer or reference that targets a `DenseSkewMatrix`.\n",
-    "\n",
-    "The preferred solution, however, would be to make `BaseMatrix::multWithVector()` a **pure virtual function**."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 13,
-   "id": "3069e8e2",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "class Vector;\n",
-    "\n",
-    "class BaseMatrix {\n",
-    "    virtual void multWithVector( const Vector& src, Vector& dst ) const = 0;\n",
-    "}"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "ec47a18b",
-   "metadata": {},
-   "source": [
-    "* A pure virtual function has no implementation in the class where it is declared. It only describes an **interface**.\n",
-    "* Adding a pure virtual function to a class makes it an **abstract class**, i.e. we cannot instantiate an object of that class.\n",
-    "* The same holds for its children (via inheritance), as long as they do not implement the method."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "24c9d364",
-   "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
-}
+{"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":"# Polymorphic or Virtual Classes","metadata":{},"id":"1a6233be"},{"cell_type":"markdown","source":"## Virtual Functions","metadata":{},"id":"b6f1b161-e13c-4f2f-bb7c-9b2ecbdb8c1a"},{"cell_type":"markdown","source":"We return to our example from <a href=\"https://www.hanser-kundencenter.de/fachbuch/artikel/9783446458468\">[Go19]</a> and extend it a little.","metadata":{},"id":"7ec80016"},{"cell_type":"code","source":"#include <iostream>\n\nclass person {\n\npublic:\n  person( const std::string& name ) : name(name) {};\n\n  void all_info() const {\n    std::cout << \"[person]   My name is \" << name << std::endl;\n  }\n\nprotected:\n  std::string name;\n};","metadata":{"trusted":true},"execution_count":25,"outputs":[],"id":"7942848b"},{"cell_type":"code","source":"class student : public person {\n\npublic:\n  student( const std::string& name, const std::string program ) :\n    person(name), program(program) {}\n\n  void all_info() const {\n    std::cout << \"[student]  My name is \" << name\n              << \", I study \" << program << std::endl;\n  }\n\nprivate:\n  std::string program;\n};","metadata":{"trusted":true},"execution_count":26,"outputs":[],"id":"f40024e2"},{"cell_type":"code","source":"class researcher : public person {\n\npublic:\n  researcher( const std::string& name, const std::string& field ) :\n    person(name), field(field) {}\n\n  void all_info() const {\n    std::cout << \"[researcher]  My name is \" << name\n              << \", I work on problems in \" << field << std::endl;\n  }\n\nprivate:\n  std::string field;\n};","metadata":{"trusted":true},"execution_count":27,"outputs":[],"id":"459a1ce0"},{"cell_type":"markdown","source":"As `student`s and `researcher`s are `person`s we can e.g. generate a vector of person pointers, where each pointer targets a different university member.","metadata":{},"id":"c5c9fb7a"},{"cell_type":"code","source":"#include <vector>\n\nstudent joe( \"Joe\", \"Geophysics\" );\nstudent jane( \"Jane\", \"Geology\" );\n\nresearcher erika( \"Erika\", \"Seismology\" );\nperson franz( \"Franz\" );\n\nstd::vector<person*> uniMembers;\n\nuniMembers.push_back( &joe );\nuniMembers.push_back( &jane );\nuniMembers.push_back( &erika );\nuniMembers.push_back( &franz );","metadata":{"trusted":true},"execution_count":28,"outputs":[],"id":"5ff4684f"},{"cell_type":"markdown","source":"* Because of inheritance, we can now have all pointers to our different people in the same vector, although the targeted objects are of different type.\n* Problem is, when we work with the vector entries and ask for info, we only get the minimal stuff from the base class ...","metadata":{},"id":"56cad921"},{"cell_type":"code","source":"for( auto memb: uniMembers ) memb->all_info();","metadata":{"trusted":true},"execution_count":29,"outputs":[{"name":"stdout","text":"[person]   My name is Joe\n[person]   My name is Jane\n[person]   My name is Erika\n[person]   My name is Franz\n","output_type":"stream"}],"id":"aebeaf35"},{"cell_type":"markdown","source":"... instead of the full records, such as","metadata":{},"id":"3f7ae736"},{"cell_type":"code","source":"jane.all_info();\nerika.all_info();","metadata":{"trusted":true},"execution_count":30,"outputs":[{"name":"stdout","text":"[student]  My name is Jane, I study Geology\n[researcher]  My name is Erika, I work on problems in Seismology\n","output_type":"stream"}],"id":"445c4d28"},{"cell_type":"markdown","source":"The solution to this is to make our classes **polymorphic**.\n\n***\n### Definition \nA class that contains at least one **virtual function** is called **polymorphic** or **virtual**.\n\n***","metadata":{},"id":"977efc72"},{"cell_type":"markdown","source":"Let us change our example by making `all_info()` a virtual function.","metadata":{},"id":"c0f70535-8833-42c4-b1ea-fd5dcdca72f2"},{"cell_type":"code","source":"#include <iostream>\n\nclass person {\n\npublic:\n  person( const std::string& name ) : name(name) {};\n\n  virtual void all_info() const {                                   // <- one small change only ;-)\n    std::cout << \"[person]      My name is \" << name << std::endl;\n  }\n\nprotected:\n  std::string name;\n};\n\nclass student : public person {\n\npublic:\n  student( const std::string& name, const std::string program ) :\n    person(name), program(program) {}\n\n  void all_info() const {\n    std::cout << \"[student]     My name is \" << name\n              << \", I study \" << program << std::endl;\n  }\n\nprivate:\n  std::string program;\n};\n\nclass researcher : public person {\n\npublic:\n  researcher( const std::string& name, const std::string& field ) :\n    person(name), field(field) {}\n\n  void all_info() const {\n    std::cout << \"[researcher]  My name is \" << name\n              << \", I work on problems in \" << field << std::endl;\n  }\n\nprivate:\n  std::string field;\n};","metadata":{"trusted":true},"execution_count":31,"outputs":[],"id":"4b596bd2"},{"cell_type":"code","source":"#include <vector>\n\nstudent joe( \"Joe\", \"Geophysics\" );\nstudent jane( \"Jane\", \"Geology\" );\n\nresearcher erika( \"Erika\", \"Seismology\" );\nperson franz( \"Franz\" );\n\nstd::vector<person*> uniMembers;\n\nuniMembers.push_back( &joe );\nuniMembers.push_back( &jane );\nuniMembers.push_back( &erika );\nuniMembers.push_back( &franz );\n\nfor( auto memb: uniMembers ) memb->all_info();","metadata":{"trusted":true},"execution_count":32,"outputs":[{"name":"stdout","text":"[student]     My name is Joe, I study Geophysics\n[student]     My name is Jane, I study Geology\n[researcher]  My name is Erika, I work on problems in Seismology\n[person]      My name is Franz\n","output_type":"stream"}],"id":"12bebbf9"},{"cell_type":"markdown","source":"#### Explanation \nSo what is the difference here? Whenever we work with a **pointer** `pVar` or a **reference** `rVar` to a class and invoke a function `myFunc()` via that on the target the compiler will check the following:\n\n1. What is the **static type** of `pVal` and or `pVar`, i.e. how were they declared?\n1. Does that class have a method `myFunc()`?\n1. Is `myFunc()` accessible, i.e. public, or not, i.e. private?\n1. Is it a **virtual function**?\n   * No: Then invoke it.\n   * Yes: Check what the **dynamic type** is of `pVal` or `pVar`, i.e. the type of the object they target.\n   Then invoke `myFunc()` for that type.","metadata":{},"id":"ef04a619"},{"cell_type":"markdown","source":"#### Remark 1 \nThis only works for pointers and references, but not for variables, even if they are initialised or copy constructed from a child object.","metadata":{},"id":"ae46b4e3"},{"cell_type":"code","source":"person alias{joe};\nalias.all_info();","metadata":{"trusted":true},"execution_count":33,"outputs":[{"name":"stdout","text":"[person]      My name is Joe\n","output_type":"stream"}],"id":"f371e175-cbc1-45e4-b8bb-06b8ebc92ef1"},{"cell_type":"markdown","source":"Only the parts of `joe` that belong to its `person` base class are used for the initialisation of `alias`. This is sometimes refered to as **slicing**.","metadata":{},"id":"2d6da352"},{"cell_type":"markdown","source":"#### Remark 2  \nThe decision which version of `all_info()` must be invoked **cannot** be made by the compiler, as it may not have the necessary information on the type of the target of a pointer or reference. It can only be made at **run-time**.","metadata":{},"id":"ad22ac97"},{"cell_type":"markdown","source":"### Terminology\nSince the decision which virtual method is invoked on a pointer or reference to a polymorphic object is performed at run-time, one calls this **late** or **dynamic binding**.\n\nIt constitutes a form of **dynamic polymorphism**, as opposed to the static polymorphism of overloading or templates, which get's resolved at compile-time.","metadata":{},"id":"bcb61161"},{"cell_type":"markdown","source":"### Costs\nIn order to be able to correctly dispatch the virtual function call at runtime, the compiler generates a <a href=\"https://en.wikipedia.org/wiki/Virtual_method_table\">**virtual function table**</a> (also known as **virtual method table**, **vtable**, **dispatch table**). The necessary table lookup constitutes an indirection and increases the costs for the function invokation.\n\nIf your function is short (i.e. does not perform a lot of work) then this extra overhead can be critically significant. If you function is long is will be negligible.","metadata":{},"id":"370a4417"},{"cell_type":"markdown","source":"### Overriding\n#### Pitfalls","metadata":{},"id":"e27f36b9"},{"cell_type":"markdown","source":"In our example all child classes (`student` and `researcher`) have implemented their own version of `all_info()` and, thus, **overridden** the one from the base class. This is, however, not required. If the base class method is not overridden in a child, the base class method will simply be used.","metadata":{},"id":"960b3f74"},{"cell_type":"code","source":"class staff : public person{\n    using person::person;\n};","metadata":{"trusted":true},"execution_count":34,"outputs":[],"id":"99352379"},{"cell_type":"code","source":"person* secretary = new staff( \"Linda\" );\nsecretary->all_info();","metadata":{"trusted":true},"execution_count":35,"outputs":[{"name":"stdout","text":"[person]      My name is Linda\n","output_type":"stream"}],"id":"454ccaaf"},{"cell_type":"markdown","source":"Especially in larger code bases it can be come tedious to not lose the overview on which member functions are virtual and which are not. Or whether we are overriding the correct version of a method.","metadata":{},"id":"80e7e3b3"},{"cell_type":"code","source":"#include <iostream>\n\nstruct A {\n    void func1() { std::cout << \"A::func1 is executing\" << std::endl; };\n    virtual void func2( double a ) { std::cout << \"func2 from A: a = \" << a << std::endl; }; \n    virtual void func3() const { std::cout << \"A::func3 is executing\" << std::endl; }; \n};\n\n\nstruct B : public A {\n    void func1() { std::cout << \"B::func1 is executing\" << std::endl; };\n    virtual void func2( int a ) { std::cout << \"func2 from B: a = \" << a << std::endl; };\n    void func3() { std::cout << \"B::func3 is executing\" << std::endl; }; \n};","metadata":{"trusted":true},"execution_count":36,"outputs":[],"id":"bd457522"},{"cell_type":"code","source":"A* obj = new B;\nobj->func1();\nobj->func2( 2 );\nobj->func3();","metadata":{"trusted":true},"execution_count":37,"outputs":[{"name":"stdout","text":"A::func1 is executing\nfunc2 from A: a = 2\nA::func3 is executing\n","output_type":"stream"}],"id":"4a0a85ba"},{"cell_type":"markdown","source":"This did not give the expected results as:\n1. `A::func1` is not virtual, so we don't overide.\n1. While `A::func2` is virtual, the interface of `B::func2` is different, so again no override.\n1. Similarly, while `A::func3` is virtual, its signature is different to that of `B::func3` because of the `const`.\n\nA smart compiler might warn us on the latter two issues, if we ask for it. But it will not warn about the first one:","metadata":{},"id":"6414fc0e"},{"cell_type":"code","source":"%%file fail.cpp\n\n#include <iostream>\n\nstruct A {\n    void func1() { std::cout << \"A::func1 is executing\" << std::endl; };\n    virtual void func2( double a ) { std::cout << \"func2 from A: a = \" << a << std::endl; }; \n    virtual void func3() const { std::cout << \"A::func3 is executing\" << std::endl; }; \n};\n\n\nstruct B : public A {\n    void func1() { std::cout << \"B::func1 is executing\" << std::endl; };\n    virtual void func2( int a ) { std::cout << \"func2 from B: a = \" << a << std::endl; };\n    void func3() { std::cout << \"B::func3 is executing\" << std::endl; }; \n};","metadata":{"trusted":true},"execution_count":39,"outputs":[{"name":"stdout","text":"Overwriting fail.cpp\n","output_type":"stream"}],"id":"3c824171"},{"cell_type":"code","source":"!clang++ -Wall -Wextra -c fail.cpp","metadata":{"trusted":true},"execution_count":40,"outputs":[{"name":"stdout","text":"fail.cpp:13:18: warning: 'B::func2' hides overloaded virtual function [-Woverloaded-virtual]\n    virtual void func2( int a ) { std::cout << \"func2 from B: a = \" << a << std::endl; };\n                 ^\nfail.cpp:6:18: note: hidden overloaded virtual function 'A::func2' declared here: type mismatch at 1st parameter ('double' vs 'int')\n    virtual void func2( double a ) { std::cout << \"func2 from A: a = \" << a << std::endl; }; \n                 ^\nfail.cpp:14:10: warning: 'B::func3' hides overloaded virtual function [-Woverloaded-virtual]\n    void func3() { std::cout << \"B::func3 is executing\" << std::endl; }; \n         ^\nfail.cpp:7:18: note: hidden overloaded virtual function 'A::func3' declared here: different qualifiers (const vs none)\n    virtual void func3() const { std::cout << \"A::func3 is executing\" << std::endl; }; \n                 ^\n2 warnings generated.\n","output_type":"stream"}],"id":"29c729c5"},{"cell_type":"markdown","source":"#### Specifier: override\nHowever, we can use the **override** specifier to indicate that we are (intending :) to override a virtual method of the base class. Then the compiler will generate an error, if this fails:","metadata":{},"id":"46b31bab-6112-45c8-8bf3-5137f08169a4"},{"cell_type":"code","source":"%%file fail.cpp\n\n#include <iostream>\n\nstruct A {\n    void func1() { std::cout << \"A::func1 is executing\" << std::endl; };\n    virtual void func2( double a ) { std::cout << \"func2 from A: a = \" << a << std::endl; }; \n    virtual void func3() const { std::cout << \"A::func3 is executing\" << std::endl; }; \n};\n\n\nstruct B : public A {\n    void func1() override { std::cout << \"B::func1 is executing\" << std::endl; };\n    virtual void func2( int a ) override { std::cout << \"func2 from B: a = \" << a << std::endl; };\n    void func3() override { std::cout << \"B::func3 is executing\" << std::endl; }; \n};","metadata":{"trusted":true},"execution_count":41,"outputs":[{"name":"stdout","text":"Overwriting fail.cpp\n","output_type":"stream"}],"id":"8ab90c4e-a3a3-4d26-8be1-6783e75d8bdb"},{"cell_type":"code","source":"!g++ fail.cpp","metadata":{"trusted":true},"execution_count":42,"outputs":[{"name":"stdout","text":"fail.cpp:12:10: error: ‘void B::func1()’ marked ‘override’, but does not override\n     void func1() override { std::cout << \"B::func1 is executing\" << std::endl; };\n          ^~~~~\nfail.cpp:13:18: error: ‘virtual void B::func2(int)’ marked ‘override’, but does not override\n     virtual void func2( int a ) override { std::cout << \"func2 from B: a = \" << a << std::endl; };\n                  ^~~~~\nfail.cpp:14:10: error: ‘void B::func3()’ marked ‘override’, but does not override\n     void func3() override { std::cout << \"B::func3 is executing\" << std::endl; };\n          ^~~~~\n","output_type":"stream"}],"id":"f4c9ca56-443e-477c-a1ee-869de3d44341"},{"cell_type":"markdown","source":"#### Speficier: final\nThe `final` specifier allows is to express that this is the final implementation of a virtual method. Further child classes are then not allowed to override it anymore.","metadata":{},"id":"cd972c82-a6c3-4d04-95ec-2880d78f4e43"},{"cell_type":"code","source":"%%file final.cpp\n\n#include <iostream>\n\nclass GrandMother {\npublic:\n  virtual void doIt( int a ) = 0;\n  void func() {};\n};\n\nclass Mother : public GrandMother {\npublic:\n  void doIt( int a ) override // final // (1) creates an error in Daughter\n  {\n    std::cout << a << \" + 3 = \" << a+3 << std::endl;\n  }\n  // void func() final {}; // (2) will fail as GrandMother::func is not virtual\n};\n\nclass Daughter : public Mother {\npublic:\n  // void doIt( int a ) override { // (3)\n  // void doIt( int a ) final {\n  void doIt( int a ) override final {\n  // void doIt( int a ) {\n    std::cout << a << \" * 3 = \" << a*3 << std::endl;\n  }\n};\n\nint main() {\n  Mother mom;\n  mom.doIt( 1 ); \n  Daughter sally;\n  sally.doIt( 2 );\n}","metadata":{"trusted":true},"execution_count":46,"outputs":[{"name":"stdout","text":"Overwriting final.cpp\n","output_type":"stream"}],"id":"6c7d3d27-6622-497c-a621-ec8a207ae1ae"},{"cell_type":"code","source":"!g++ final.cpp","metadata":{"trusted":true},"execution_count":47,"outputs":[],"id":"55d0dcc1-2f25-4b27-812c-46b1009c6881"},{"cell_type":"code","source":"!./a.out","metadata":{"trusted":true},"execution_count":48,"outputs":[{"name":"stdout","text":"1 + 3 = 4\n2 * 3 = 6\n","output_type":"stream"}],"id":"ae0745fb-02d6-4a15-b59d-08720bdcb1cc"},{"cell_type":"markdown","source":"**Note** that both speficiers `override` and `final` are **optional**. Thus, it is formally not required e.g. to combine `final` with `override`.","metadata":{},"id":"8f3dd806-ae3a-47d9-8380-32b940567b24"},{"cell_type":"markdown","source":"## Pure Virtual Functions and Abstract Classes","metadata":{},"id":"413b3e71"},{"cell_type":"markdown","source":"Consider the following application scenario:\n\n- We want to implement four specialised matrix classes\n  - `DenseMatrix`\n  - `DenseSymMatrix`\n  - `SparseMatrix`\n  - `SparseSymMatrix`\n- They all should be children of a common `BaseMatrix` base class.\n- All of them should provide a method `multWithVector()` with the same signature.\n- We want to be able to invoke that method on a base class pointer or reference.\n\n This gives rise to the following questions:\n 1. How should `BaseMatrix::multWithVector()` be implemented?\n 1. Can we enforce that someone who adds another child, say `DenseSkewMatrix` does not forget to implement `DenseSkewMatrix::multWithVector()`?\n\nA sensible implementation of `BaseMatrix::multWithVector()` will not be possible, as the base class has no knowledge on the details of how its children store their matrices. We could only do an empty implementation or one that e.g. throws an exception. The latter would at least lead to a runtime crash, if we call `multWithVector()` on a base class pointer or reference that targets a `DenseSkewMatrix` and the latter did forget to override.\n\nThe preferred solution, however, would be to make `BaseMatrix::multWithVector()` a **pure virtual function**.","metadata":{},"id":"ebb14ead"},{"cell_type":"code","source":"class Vector;\n\nclass BaseMatrix {\n    virtual void multWithVector( const Vector& src, Vector& dst ) const = 0;\n}","metadata":{},"execution_count":13,"outputs":[],"id":"3069e8e2"},{"cell_type":"markdown","source":"* A pure virtual function has no implementation in the class where it is declared. It only describes an **interface**.\n* Adding a pure virtual function to a class makes it an **abstract class**, i.e. we cannot instantiate an object of that class.\n* The same holds for its children (via inheritance), as long as they do not implement the method.","metadata":{},"id":"ec47a18b"},{"cell_type":"code","source":"%%file pure.cpp\n\n#include <iostream>\n\nclass Interface {\n\n  virtual void setValue( double v ) = 0;\n  virtual double getValue() = 0;\n\n};\n\nclass VariantA : public Interface {\nprivate:\n  double val_;\npublic:\n virtual void setValue( double v ) override final { val_ = v; };\n};\n\nclass VariantB : public Interface {\nprivate:\n  double val_;\npublic:\n  virtual void setValue( double v ) override final { val_ = v; };\n  double getValue() { return val_; };\n};\n\nint main( void ) {\n  // Interface uninstantiable;\n  // VariantA obj1;\n  VariantB obj2;\n}","metadata":{"trusted":true},"execution_count":56,"outputs":[{"name":"stdout","text":"Overwriting pure.cpp\n","output_type":"stream"}],"id":"24c9d364"},{"cell_type":"code","source":"!g++ pure.cpp","metadata":{"trusted":true},"execution_count":57,"outputs":[],"id":"a6159a96-102e-478f-8e06-68e51e77e1d0"},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[],"id":"400a8a90-8f2a-468c-a9ba-4f124029858e"}]}
\ No newline at end of file