diff --git a/notebooks/13_Assorted_Examples.ipynb b/notebooks/13_Assorted_Examples.ipynb
index 949bd6551a032ca6793929de48e9cde97c99df61..cb37a0024728c4ad87f5c0cb65369ab08cd594d5 100644
--- a/notebooks/13_Assorted_Examples.ipynb
+++ b/notebooks/13_Assorted_Examples.ipynb
@@ -1 +1 @@
-{"metadata":{"kernelspec":{"name":"xcpp17","display_name":"C++17","language":"C++17"},"language_info":{"codemirror_mode":"text/x-c++src","file_extension":".cpp","mimetype":"text/x-c++src","name":"c++","version":"17"}},"nbformat_minor":5,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Assorted other Examples","metadata":{},"id":"9e611ffc-67dc-4bf7-ad80-747680965827"},{"cell_type":"markdown","source":"Templates form one of the main sublanguages of C++ (Scott Meyers, \"Effective C++\", 2009).\nWe have, by far, not covered all aspects of this. The following diagram list the main areas Rainer Grimm intends to deal with in his current Templates part of\n<a href=\"https://www.grimm-jaud.de/index.php/blog\">Modernes C++</a>:\n\n<img src=\"../images/Topics_in_Templates.png\" width=\"90%\">\n\nTopics marked in yellow, are the ones we already talked about. Those in light red and blue are ones where either some important aspects are still missing, or that we have not covered, yet.\n\nThe plan for this notebook is to take a brief look at these.","metadata":{},"id":"1bb13e1a-64a8-4a7b-9ac9-08189ed15574"},{"cell_type":"markdown","source":"## Template Metaprogramming\n\nQuoting from Wikipedia:\n> <a href=\"https://en.wikipedia.org/wiki/Metaprogramming\">**Metaprogramming**</a> is a programming technique in which computer programs have the ability to treat other programs as their data. It means that a program can be designed to read, generate, analyze or transform other programs, and even modify itself while running.\n\n> <a href=\"https://en.wikipedia.org/wiki/Template_metaprogramming\">Template Metaprogramming</a> is a metaprogramming technique in which templates are used by a compiler to generate temporary source code, which is merged by the compiler with the rest of the source code and then compiled. The output of these templates can include compile-time constants, data structures, and complete functions. The use of templates can be thought of as compile-time polymorphism.\n\n\n\nExamine the example below taken from Jürgen Lemke, \"C++-Metaprogrammierung\", Springer, 2016.","metadata":{},"id":"d3377acf-83a4-480d-bee6-4e0520f4d476"},{"cell_type":"code","source":"%%file factorial.cpp\n\n#include <iostream>\n\n// general struct\ntemplate <unsigned int i>\nstruct TFactorial {\n  enum { eValue = i * TFactorial<i-1>::eValue };\n};\n\n\n// struct for base case\ntemplate <>\nstruct TFactorial<0> {\n  enum { eValue = 1 };\n};\n\n\nint main( void ) {\n\n  std::cout << \"factorial of 5 is \"\n            << TFactorial<5>::eValue\n            << std::endl;\n\n  return 0;\n}","metadata":{"trusted":true},"execution_count":1,"outputs":[{"name":"stdout","text":"Writing factorial.cpp\n","output_type":"stream"}],"id":"1584a4ef-cafe-44e5-8818-016f3d5e2003"},{"cell_type":"code","source":"!g++ factorial.cpp; ./a.out","metadata":{"trusted":true},"execution_count":2,"outputs":[{"name":"stdout","text":"factorial of 5 is 120\n","output_type":"stream"}],"id":"ff10a24d-af46-4662-8fe1-4ed814778dbc"},{"cell_type":"markdown","source":"The catch here is that the complete computation of 5! is actually performed by the compiler. When we run the executable only the result is printed to the screen. With enough effort we could also make that a part of the compilation step.","metadata":{},"id":"3e8bbe24"},{"cell_type":"markdown","source":"## Template Template Parameters\n\nSo far our template parameters were either\n- type parameters (standard datatypes, classes, ...)\n- non-type parameters (e.g. integer types)\n\nHowever, we can also use class templates as template parameters. These are refered to as\n**template template parameters**.\n\nBefore we examine the details of this. Let us start with an example where we might want to use this.\nAssume that we work with finite element functions and have the following template classes for two standard FE spaces: ","metadata":{},"id":"ff86bb78"},{"cell_type":"code","source":"#include <iostream>\n\ntemplate< typename ValueType >\nclass P1Function {\npublic:\n  void info() const {\n    std::cout << \"Finite Element Function from P1 Lagrange Space\"\n              << \" (ValueType = \" << typeid( ValueType ).name()\n              << \")\" << std::endl;\n  }\n};\n\ntemplate< typename ValueType >\nclass P2Function {\npublic:\n  void info() const {\n    std::cout << \"Finite Element Function from P2 Lagrange Space\"\n              << \" (ValueType = \" << typeid( ValueType ).name()\n              << \")\" << std::endl;\n  }\n};","metadata":{"trusted":true},"execution_count":3,"outputs":[],"id":"c4fae9a9"},{"cell_type":"markdown","source":"The `ValueType` parameter will allow us to instantiate FE functions using different datatypes for their degrees of freedom.\n- We might e.g. use double or float in mixed precision programming.\n- Use `unsigned long int` for enumerating the DoFs when assembling a matrix-vector representation of the FE problem.\n\nNow assume we want to write an operator class representing an operator that maps an FE function onto another FE function from the same space. We want the operator to be a template class and could use our standard approach for this:","metadata":{},"id":"63cd43d6"},{"cell_type":"code","source":"template< typename FunctionType >\nclass OperatorV1 {\npublic:\n  void apply( const FunctionType& src, FunctionType& dst ) {\n    std::cout << \"src: \";\n    src.info();\n    std::cout << \"dst: \";\n    dst.info();\n  }\n};","metadata":{"trusted":true},"execution_count":4,"outputs":[],"id":"e8b9fb8a"},{"cell_type":"code","source":"int main() {\n  P2Function< double > src, dst;\n  OperatorV1< P2Function< double > > laplacian;\n  std::cout << \"-> applying laplacian\" << std::endl;\n  laplacian.apply( src, dst );\n    \n  OperatorV1< std::string > lazyFail;   // remember: implicit instantiation is lazy\n}\n    \nmain();","metadata":{"trusted":true},"execution_count":5,"outputs":[{"name":"stdout","text":"-> applying laplacian\nsrc: Finite Element Function from P2 Lagrange Space (ValueType = d)\ndst: Finite Element Function from P2 Lagrange Space (ValueType = d)\n","output_type":"stream"}],"id":"0483e979"},{"cell_type":"markdown","source":"The approach works, of course. However, it has some properties that might not be optimal in all settings:\n1. We have note expressed that our operator class is intended to work with certain template arguments, only. ($\\rightarrow$ see lazyFail above and *Concepts* in C++20).\n1. There is no direct way to derive from the argument provided for the `FunctionType` template parameter the fact that it is an instance of template class `P2Function` (at least in C++17 and to the best of my knowledge :-). What if we need to generate in the operator an auxillary function of another datatype, e.g. `P2Function<int>`?\n\nAn approach that resolves these issues is to use a **template template parameter**:","metadata":{},"id":"60732d5b-c097-4fcb-9e2b-6debac9e6d34"},{"cell_type":"code","source":"template< template < typename > class func_t >\nclass OperatorV2 {\npublic:\n  OperatorV2() {\n    func_t< double > aux1;\n    func_t< int > aux2;\n    std::cout << \"aux1: \"; aux1.info();\n    std::cout << \"aux2: \"; aux2.info();\n  }\n\n  template< typename ValueType >\n  void apply( const func_t< ValueType >& src, func_t< ValueType >& dst )\n  {\n    std::cout << \"src: \";\n    src.info();\n    std::cout << \"dst: \";\n    dst.info();\n  }\n\n};","metadata":{"trusted":true},"execution_count":6,"outputs":[],"id":"f9b9cb47"},{"cell_type":"code","source":"int main() {\n\n  std::cout << \"\\n-> instantiating oper\" << std::endl;\n  OperatorV2< P1Function > oper;\n\n  std::cout << \"\\n-> applying oper\" << std::endl;\n  P1Function< float > srcP1, dstP1;\n  oper.apply( srcP1, dstP1 );   // instantiates OperatorV2::apply for float\n}\n\nmain();","metadata":{"trusted":true},"execution_count":7,"outputs":[{"name":"stdout","text":"\n-> instantiating oper\naux1: Finite Element Function from P1 Lagrange Space (ValueType = d)\naux2: Finite Element Function from P1 Lagrange Space (ValueType = i)\n\n-> applying oper\nsrc: Finite Element Function from P1 Lagrange Space (ValueType = f)\ndst: Finite Element Function from P1 Lagrange Space (ValueType = f)\n","output_type":"stream"}],"id":"1b69d421"},{"cell_type":"markdown","source":"Note that the example also demonstrates the use of a **template member function**, `OperatorV2::apply()`.\n\n---\nIf we are only interested in retaining the information on the template class, we can also use an approach with two template parameters:","metadata":{},"id":"053c49a5"},{"cell_type":"code","source":"template< template < typename > class func_t, typename value_t >\nclass OperatorV3 {\npublic:\n  OperatorV3() {\n    func_t< value_t > aux1;\n    func_t< int > aux2;\n    std::cout << \"aux1: \"; aux1.info();\n    std::cout << \"aux2: \"; aux2.info();\n  }\n\n  void apply( const func_t< value_t >& src, func_t< value_t >& dst )\n  {\n    std::cout << \"src: \";\n    src.info();\n    std::cout << \"dst: \";\n    dst.info();\n  }\n\n};","metadata":{"trusted":true},"execution_count":8,"outputs":[],"id":"7f98cebb"},{"cell_type":"code","source":"int main() {\n\n  std::cout << \"\\n-> instantiating mass oper\" << std::endl;\n  // OperatorV3< P1Function< float > > mass;\n  OperatorV3< P1Function, float > mass;\n    \n  std::cout << \"\\n-> applying mass oper\" << std::endl;\n  P1Function< float > src, dst;\n  mass.apply( src, dst );\n}\n\nmain();","metadata":{"trusted":true},"execution_count":9,"outputs":[{"name":"stdout","text":"\n-> instantiating mass oper\naux1: Finite Element Function from P1 Lagrange Space (ValueType = f)\naux2: Finite Element Function from P1 Lagrange Space (ValueType = i)\n\n-> applying mass oper\nsrc: Finite Element Function from P1 Lagrange Space (ValueType = f)\ndst: Finite Element Function from P1 Lagrange Space (ValueType = f)\n","output_type":"stream"}],"id":"dd6a1f5d"},{"cell_type":"markdown","source":"## Constexpr If\n\n`if constexpr` was introduced in C++17 and consititutes a form of *conditional compilation* in the context of templates. Let us directly plunge into a first example:","metadata":{},"id":"80018e40-0bbe-4949-b352-f1467e829df9"},{"cell_type":"code","source":"%%file demo.cpp\n\n#include <iostream>\n\nclass A {\npublic:\n  void sayHello() { std::cout << \"Class A says 'Hello'\" << std::endl;\n  }\n};\n\nclass B {\npublic:\n  void gruss() { std::cout << \"Guten Morgen!\" << std::endl;\n  }\n};\n\ntemplate< typename T >\nvoid checkMessage( T& obj ) {\n  if ( std::is_same_v< A, T > ) {\n    obj.sayHello();\n  }\n  else if( std::is_same_v< B, T > ) {\n    obj.gruss();\n  }\n}\n\nint main() {\n  A objTypeA;\n  checkMessage( objTypeA );\n}","metadata":{"trusted":true},"execution_count":10,"outputs":[{"name":"stdout","text":"Writing demo.cpp\n","output_type":"stream"}],"id":"4d05e6d4-b370-40a6-a5ad-334bbe8ed3be"},{"cell_type":"code","source":"!g++ -std=c++17 demo.cpp","metadata":{"trusted":true},"execution_count":11,"outputs":[{"name":"stdout","text":"demo.cpp: In instantiation of ‘void checkMessage(T&) [with T = A]’:\ndemo.cpp:28:26:   required from here\ndemo.cpp:22:9: error: ‘class A’ has no member named ‘gruss’\n     obj.gruss();\n     ~~~~^~~~~\n","output_type":"stream"}],"id":"00c57191-2b46-4181-ad72-4595ac882d03"},{"cell_type":"markdown","source":"The *constexpr if* allows us to resolve this issue:","metadata":{},"id":"451b033c-a240-4b1d-b94b-5b0d7dc75d90"},{"cell_type":"code","source":"%%file demo.cpp\n\n#include <iostream>\n\nclass A {\npublic:\n  void sayHello() { std::cout << \"Class A says 'Hello'\" << std::endl;\n  }\n};\n\nclass B {\npublic:\n  void gruss() { std::cout << \"Guten Morgen!\" << std::endl;\n  }\n};\n\ntemplate< typename T >\nvoid checkMessage( T& obj ) {\n  if constexpr( std::is_same_v< A, T > ) {    // <- here is the important change!\n    obj.sayHello();\n  }\n  else if( std::is_same_v< B, T > ) {\n    obj.gruss();\n    // double a; a->foo();\n  }\n}\n\nint main() {\n  A objTypeA;\n  checkMessage( objTypeA );\n\n  B objTypeB;\n  checkMessage( objTypeB );\n}","metadata":{"trusted":true},"execution_count":12,"outputs":[{"name":"stdout","text":"Overwriting demo.cpp\n","output_type":"stream"}],"id":"6be129fa"},{"cell_type":"code","source":"!g++ -std=c++17 demo.cpp","metadata":{"trusted":true},"execution_count":13,"outputs":[],"id":"1ac9c0ba"},{"cell_type":"code","source":"!./a.out","metadata":{"trusted":true},"execution_count":14,"outputs":[{"name":"stdout","text":"Class A says 'Hello'\nGuten Morgen!\n","output_type":"stream"}],"id":"083cc1e4"},{"cell_type":"markdown","source":"What is the difference?\n\nThe condition in an *constexpr if* must be in general be a <a href=\"https://en.cppreference.com/w/cpp/language/constant_expression#Converted_constant_expression\">contextually converted constant expression of type bool</a>.\n\nIn our template example it is something the compiler can check at instantiation! In this case the branch for which condition evaluates to *true* is instantiated, the other not! This is what makes the difference.\n\nNote that the *false* branch, while not being instantiated, must still be syntactically correct. Remember the **two-phase lookup** we discussed. Not being instantiated means the second phase is skipped, but the code still needs to pass the first phase!\n\nThus, this is not equivalent to conditional compilation with preprocessing directives. As can be seen from the following example from cppreference.com:","metadata":{},"id":"c99ff76a"},{"cell_type":"code","source":"void f() {\n    if constexpr(false) {\n        int i = 0;\n        int *p = i; // Error even though in discarded statement\n    }\n}","metadata":{"trusted":true},"execution_count":15,"outputs":[{"name":"stderr","text":"input_line_15:4:14: error: cannot initialize a variable of type 'int *' with an lvalue of type 'int'\n        int *p = i; // Error even though in discarded statement\n             ^   ~\n","output_type":"stream"},{"ename":"Interpreter Error","evalue":"","traceback":["Interpreter Error: "],"output_type":"error"}],"id":"ed62c962"},{"cell_type":"markdown","source":"---\nA maybe more realistic example for the use of *constexpr if* is the following from the <a href=\"https://blog.tartanllama.xyz/if-constexpr/\">blog</a> by Sy Brand. Note that this also features automatic return type deduction:","metadata":{},"id":"bd46e337"},{"cell_type":"code","source":"#include <type_traits>\n\ntemplate <typename T>\nauto get_value(T t) {\n    if constexpr (std::is_pointer_v<T>)\n        return *t;\n    else\n        return t;\n}","metadata":{"trusted":true},"execution_count":16,"outputs":[],"id":"c273e25c-652a-461d-b351-3123afccbc11"},{"cell_type":"markdown","source":"Now let us test-drive this:","metadata":{},"id":"3c1ba823-1b7e-4d7e-be29-59b0c1782579"},{"cell_type":"code","source":"#include <iostream>\n\nint main() {\n\n  int  a = 2;\n  int* p = &a;\n\n  std::cout << \"direct access ..... a = \" << get_value( a ) << std::endl;\n  std::cout << \"indirect access ... a = \" << get_value( p ) << std::endl;\n\n}\n\nmain();","metadata":{"trusted":true},"execution_count":17,"outputs":[{"name":"stdout","text":"direct access ..... a = 2\nindirect access ... a = 2\n","output_type":"stream"}],"id":"df64d78d-eecb-408d-a9db-1b1a72716de2"},{"cell_type":"markdown","source":"When we inspect the instantiations with <a href=\"https://cppinsights.io/\">cppinsights</a> we see that indeed only the valid branch gets instantiated:\n<center><img src=\"../images/cppInsights02.png\" width=\"70%\"></center>","metadata":{},"id":"25c99ad6"},{"cell_type":"markdown","source":"The *constexpr if* allows to simplify templates by reducing the need for specialisations, like in the following example using template meta-programming:","metadata":{},"id":"396d5d0e"},{"cell_type":"code","source":"%%file power.cpp\n\n#define CONST_EXPR\n\n#ifndef CONST_EXPR\n\ntemplate< int base, unsigned int exp >\nstruct Power {\n  static int value() {\n    return base * Power< base, exp - 1u >::value();\n  }\n};\n\ntemplate< int base >\nstruct Power< base, 0 > {\n  static int value() {\n    return 1;\n  }\n};\n\n#else\n\ntemplate< int base, unsigned int exp >\nstruct Power {\n  static int value() {\n    if constexpr( exp > 0 ) {\n      return base * Power< base, exp - 1u >::value();\n    }\n    else {\n      return 1;\n    }\n  }\n};\n\n#endif\n\n#include <iostream>\n\nint main() {\n  std::cout << \"5^3 = \" << Power<5,3>::value() << std::endl;\n}","metadata":{"scrolled":true,"tags":[],"trusted":true},"execution_count":22,"outputs":[{"name":"stdout","text":"Overwriting power.cpp\n","output_type":"stream"}],"id":"4f01ee73"},{"cell_type":"code","source":"!g++ -std=c++17 power.cpp","metadata":{"trusted":true},"execution_count":23,"outputs":[],"id":"8a4bb240"},{"cell_type":"code","source":"!./a.out","metadata":{"trusted":true},"execution_count":24,"outputs":[{"name":"stdout","text":"5^3 = 125\n","output_type":"stream"}],"id":"39268b6a"},{"cell_type":"markdown","source":"## Dependent Names Revisited\nWe had encountered the concept of *non-dependent* and <a href=\"https://en.cppreference.com/w/cpp/language/dependent_name\">*dependent names*</a> in notebook # 12, when we looked at inheritance of template classes and their member functions.\n\nIn the context of dependent names the following keywords might be needed:\n* `typename`\n* `template`\n\nAssume we have the following template class:","metadata":{},"id":"b52ae491"},{"cell_type":"code","source":"template< typename T >\nclass A {\npublic:\n    using ptrType = T*;\n};","metadata":{"trusted":true},"execution_count":25,"outputs":[],"id":"8995872a"},{"cell_type":"markdown","source":"Now we write a template function that internally needs to generate a pointer ","metadata":{},"id":"60809792"},{"cell_type":"code","source":"template< typename T >\nvoid doSomething( T& obj ) {\n    A<T>::ptrType valPtr;\n}","metadata":{"trusted":true},"execution_count":26,"outputs":[{"name":"stderr","text":"input_line_21:3:18: error: expected ';' after expression\n    A<T>::ptrType valPtr;\n                 ^\n                 ;\ninput_line_21:3:19: error: use of undeclared identifier 'valPtr'\n    A<T>::ptrType valPtr;\n                  ^\n","output_type":"stream"},{"ename":"Interpreter Error","evalue":"","traceback":["Interpreter Error: "],"output_type":"error"}],"id":"f19c19b9"},{"cell_type":"markdown","source":"Hmm, what is the problem here? Let's try something else:","metadata":{},"id":"fef65d8e"},{"cell_type":"code","source":"template< typename T >\nclass foo {\n  using vType = T::valueType;\n};","metadata":{"trusted":true},"execution_count":27,"outputs":[{"name":"stderr","text":"input_line_22:3:17: error: missing 'typename' prior to dependent type name 'T::valueType'\n  using vType = T::valueType;\n                ^~~~~~~~~~~~\n                typename \n","output_type":"stream"},{"ename":"Interpreter Error","evalue":"","traceback":["Interpreter Error: "],"output_type":"error"}],"id":"975025b2"},{"cell_type":"markdown","source":"In both cases we use a name that is dependent on the template parameter `T`\n* `A<T>::ptrType`\n* `T::valueType`\n\nThe full details of this are tricky, but basically we need to help the compiler to understand that we are using a type name, by using the `typename` keyword.\n\nFrom cppreference.com:\n> In a declaration or a definition of a template, including alias template, a name that is not a member of the current instantiation and is dependent on a template parameter is not considered to be a type unless the keyword typename is used or unless it was already established as a type name, e.g. with a typedef declaration or by being used to name a base class.\n\nThat explains the error messages from the first example. `A<T>::ptrType` is not seen as a type name, but treated as a member of the template class `A<T>`.\n\nIndeed, adding the `typename` keyword fixes the problem:","metadata":{},"id":"fc965154"},{"cell_type":"code","source":"template< typename T >\nvoid doSomething( T& obj ) {\n    typename A<T>::ptrType valPtr;\n}","metadata":{"trusted":true},"execution_count":28,"outputs":[],"id":"afb191b0"},{"cell_type":"markdown","source":"A similar ambiguity problem can occur with template names:\n\n> Similarly, in a template definition, a dependent name that is not a member of the current instantiation is not considered to be a template name unless the disambiguation keyword template is used or unless it was already established as a template name.\n\nAssume we have class with a templated member function\n```c++\nclass B {\npublic:\n    template< typename T >\n    void run() {};\n};\n```\nNow we write a template function that internally generates an object, its type being the template parameter `T`, and calls its templated `run()`member function.","metadata":{},"id":"12c0fa43"},{"cell_type":"code","source":"template< typename T >\nvoid func() {\n  T obj;\n  obj.run< T >();\n}","metadata":{"scrolled":true,"trusted":true},"execution_count":29,"outputs":[{"name":"stderr","text":"input_line_24:4:7: error: use 'template' keyword to treat 'run' as a dependent template name\n  obj.run< T >();\n      ^\n      template \n","output_type":"stream"},{"ename":"Interpreter Error","evalue":"","traceback":["Interpreter Error: "],"output_type":"error"}],"id":"695e3775"},{"cell_type":"code","source":"template< typename T >\nvoid func() {\n  T obj;\n  obj.template run< T >();\n}","metadata":{"trusted":true},"execution_count":30,"outputs":[],"id":"da772d07"},{"cell_type":"markdown","source":"## CRTP: Curiously Recurring Template Pattern","metadata":{},"id":"bb14f831"},{"cell_type":"markdown","source":"The curiously recurring template patterns describes a technique, where a class B inherits from a template class A, using itself as template argument:\n\n```c++\ntemplate< typename T >\nclass A {};\n\nclass B : public A< B > {};\n```\nA nice list of usage scenarios and examples for CRTP can be found on the webpages of <a href=\"http://www.vishalchovatiya.com/crtp-c-examples/\">Vishal Chovatiya</a>. The first of these demonstrates static polymorphism:","metadata":{},"id":"0af04dfc"},{"cell_type":"code","source":"%%file crtp.cpp\n\n#include <iostream>\n\ntemplate<typename specific_animal>\nstruct animal {\n    void who() { static_cast<specific_animal*>(this)->who(); }\n};\n\nstruct dog : animal<dog> {\n    void who() { std::cout << \"dog\" << std::endl; }\n};\n\nstruct cat : animal<cat> {\n    void who() { std::cout << \"cat\" << std::endl; }\n};\n\ntemplate<typename specific_animal>\nvoid who_am_i(animal<specific_animal> &animal) {\n    animal.who();\n}\n\nint main( void ) {\n\n  cat c;\n  who_am_i(c); // prints `cat`\n\n  dog d;\n  who_am_i(d); // prints `dog`\n\n}\n","metadata":{"trusted":true},"execution_count":31,"outputs":[{"name":"stdout","text":"Writing crtp.cpp\n","output_type":"stream"}],"id":"fffce178"},{"cell_type":"code","source":"!g++ crtp.cpp","metadata":{"trusted":true},"execution_count":32,"outputs":[],"id":"1e32d10d"},{"cell_type":"code","source":"!./a.out","metadata":{"trusted":true},"execution_count":33,"outputs":[{"name":"stdout","text":"cat\ndog\n","output_type":"stream"}],"id":"da65a685"},{"cell_type":"markdown","source":"The catch here is that the `animal` class delegates the actual implementation of the `who()` member function to its children. However, in constrast to dynamic polymorphism with virtual functions this is handled at compile-time and does not induces a run-time penalty.","metadata":{},"id":"3d5e5fae"},{"cell_type":"markdown","source":"The final object counter example is taken from <a href=\"https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern#Object_counter\">Wikipedia</a>: ","metadata":{},"id":"34f3bf32"},{"cell_type":"code","source":"#include <iostream>\n\ntemplate <typename T>\nstruct counter\n{\n  static inline int objects_created = 0;\n  static inline int objects_alive = 0;\n\n  counter()\n  {\n    ++objects_created;\n    ++objects_alive;\n  }\n    \n  counter(const counter&)\n  {\n    ++objects_created;\n    ++objects_alive;\n  }\nprotected:\n  ~counter() // objects should never be removed through pointers of this type\n  {\n    --objects_alive;\n  }\n};\n\nclass X : counter<X>\n{\n  // ...\n};\n\nclass Y : counter<Y>\n{\n  // ...\n};\n\n\nint main() {\n\n  Y objY;\n  for( int k = 0; k < 2; ++k ) {\n    X* ptr = new X;\n    Y v;\n  }\n\n  std::cout << \"X created: \" << counter<X>::objects_created << std::endl;\n  std::cout << \"X alive:   \" << counter<X>::objects_alive << std::endl;\n\n  std::cout << \"Y created: \" << counter<Y>::objects_created << std::endl;\n  std::cout << \"Y alive:   \" << counter<Y>::objects_alive << std::endl;\n}","metadata":{"trusted":true},"execution_count":34,"outputs":[],"id":"fcf8be3c"},{"cell_type":"markdown","source":"What will this print?","metadata":{},"id":"f3309e3c"},{"cell_type":"code","source":"main();","metadata":{"trusted":true},"execution_count":35,"outputs":[{"name":"stdout","text":"X created: 2\nX alive:   2\nY created: 3\nY alive:   1\n","output_type":"stream"}],"id":"d761dd85"},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[],"id":"fc82d71b"}]}
\ No newline at end of file
+{"metadata":{"kernelspec":{"name":"xcpp17","display_name":"C++17","language":"C++17"},"language_info":{"codemirror_mode":"text/x-c++src","file_extension":".cpp","mimetype":"text/x-c++src","name":"c++","version":"17"}},"nbformat_minor":5,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Assorted other Examples","metadata":{},"id":"9e611ffc-67dc-4bf7-ad80-747680965827"},{"cell_type":"markdown","source":"Templates form one of the main sublanguages of C++ (Scott Meyers, \"Effective C++\", 2009).\nWe have, by far, not covered all aspects of this. The following diagram list the main areas Rainer Grimm intends to deal with in his current Templates part of\n<a href=\"https://www.grimm-jaud.de/index.php/blog\">Modernes C++</a>:\n\n<img src=\"../images/Topics_in_Templates.png\" width=\"90%\">\n\nTopics marked in yellow, are the ones we already talked about. Those in light red and blue are ones where either some important aspects are still missing, or that we have not covered, yet.\n\nThe plan for this notebook is to take a brief look at these.","metadata":{},"id":"1bb13e1a-64a8-4a7b-9ac9-08189ed15574"},{"cell_type":"markdown","source":"## Template Metaprogramming\n\nQuoting from Wikipedia:\n> <a href=\"https://en.wikipedia.org/wiki/Metaprogramming\">**Metaprogramming**</a> is a programming technique in which computer programs have the ability to treat other programs as their data. It means that a program can be designed to read, generate, analyze or transform other programs, and even modify itself while running.\n\n> <a href=\"https://en.wikipedia.org/wiki/Template_metaprogramming\">Template Metaprogramming</a> is a metaprogramming technique in which templates are used by a compiler to generate temporary source code, which is merged by the compiler with the rest of the source code and then compiled. The output of these templates can include compile-time constants, data structures, and complete functions. The use of templates can be thought of as compile-time polymorphism.\n\n\n\nExamine the example below taken from Jürgen Lemke, \"C++-Metaprogrammierung\", Springer, 2016.","metadata":{},"id":"d3377acf-83a4-480d-bee6-4e0520f4d476"},{"cell_type":"code","source":"%%file factorial.cpp\n\n#include <iostream>\n\n// general struct\ntemplate <unsigned int i>\nstruct TFactorial {\n  enum { eValue = i * TFactorial<i-1>::eValue };\n};\n\n\n// struct for base case\ntemplate <>\nstruct TFactorial<0> {\n  enum { eValue = 1 };\n};\n\n\nint main( void ) {\n\n  std::cout << \"factorial of 5 is \"\n            << TFactorial<5>::eValue\n            << std::endl;\n\n  return 0;\n}","metadata":{},"execution_count":1,"outputs":[{"name":"stdout","text":"Writing factorial.cpp\n","output_type":"stream"}],"id":"1584a4ef-cafe-44e5-8818-016f3d5e2003"},{"cell_type":"code","source":"!g++ factorial.cpp; ./a.out","metadata":{},"execution_count":2,"outputs":[{"name":"stdout","text":"factorial of 5 is 120\n","output_type":"stream"}],"id":"ff10a24d-af46-4662-8fe1-4ed814778dbc"},{"cell_type":"markdown","source":"The catch here is that the complete computation of 5! is actually performed by the compiler. When we run the executable only the result is printed to the screen. With enough effort we could also make that a part of the compilation step.","metadata":{},"id":"3e8bbe24"},{"cell_type":"markdown","source":"## Template Template Parameters\n\nSo far our template parameters were either\n- type parameters (standard datatypes, classes, ...)\n- non-type parameters (e.g. integer types)\n\nHowever, we can also use class templates as template parameters. These are refered to as\n**template template parameters**.\n\nBefore we examine the details of this. Let us start with an example where we might want to use this.\nAssume that we work with finite element functions and have the following template classes for two standard FE spaces: ","metadata":{},"id":"ff86bb78"},{"cell_type":"code","source":"#include <iostream>\n\ntemplate< typename ValueType >\nclass P1Function {\npublic:\n  void info() const {\n    std::cout << \"Finite Element Function from P1 Lagrange Space\"\n              << \" (ValueType = \" << typeid( ValueType ).name()\n              << \")\" << std::endl;\n  }\n};\n\ntemplate< typename ValueType >\nclass P2Function {\npublic:\n  void info() const {\n    std::cout << \"Finite Element Function from P2 Lagrange Space\"\n              << \" (ValueType = \" << typeid( ValueType ).name()\n              << \")\" << std::endl;\n  }\n};","metadata":{},"execution_count":3,"outputs":[],"id":"c4fae9a9"},{"cell_type":"markdown","source":"The `ValueType` parameter will allow us to instantiate FE functions using different datatypes for their degrees of freedom.\n- We might e.g. use double or float in mixed precision programming.\n- Use `unsigned long int` for enumerating the DoFs when assembling a matrix-vector representation of the FE problem.\n\nNow assume we want to write an operator class representing an operator that maps an FE function onto another FE function from the same space. We want the operator to be a template class and could use our standard approach for this:","metadata":{},"id":"63cd43d6"},{"cell_type":"code","source":"template< typename FunctionType >\nclass OperatorV1 {\npublic:\n  void apply( const FunctionType& src, FunctionType& dst ) {\n    std::cout << \"src: \";\n    src.info();\n    std::cout << \"dst: \";\n    dst.info();\n  }\n};","metadata":{},"execution_count":4,"outputs":[],"id":"e8b9fb8a"},{"cell_type":"code","source":"int main() {\n  P2Function< double > src, dst;\n  OperatorV1< P2Function< double > > laplacian;\n  std::cout << \"-> applying laplacian\" << std::endl;\n  laplacian.apply( src, dst );\n    \n  OperatorV1< std::string > lazyFail;   // remember: implicit instantiation is lazy\n}\n    \nmain();","metadata":{},"execution_count":5,"outputs":[{"name":"stdout","text":"-> applying laplacian\nsrc: Finite Element Function from P2 Lagrange Space (ValueType = d)\ndst: Finite Element Function from P2 Lagrange Space (ValueType = d)\n","output_type":"stream"}],"id":"0483e979"},{"cell_type":"markdown","source":"The approach works, of course. However, it has some properties that might not be optimal in all settings:\n1. We have note expressed that our operator class is intended to work with certain template arguments, only. ($\\rightarrow$ see lazyFail above and *Concepts* in C++20).\n1. There is no direct way to derive from the argument provided for the `FunctionType` template parameter the fact that it is an instance of template class `P2Function` (at least in C++17 and to the best of my knowledge :-). What if we need to generate in the operator an auxillary function of another datatype, e.g. `P2Function<int>`?\n\nAn approach that resolves these issues is to use a **template template parameter**:","metadata":{},"id":"60732d5b-c097-4fcb-9e2b-6debac9e6d34"},{"cell_type":"code","source":"template< template < typename > class func_t >\nclass OperatorV2 {\npublic:\n  OperatorV2() {\n    func_t< double > aux1;\n    func_t< int > aux2;\n    std::cout << \"aux1: \"; aux1.info();\n    std::cout << \"aux2: \"; aux2.info();\n  }\n\n  template< typename ValueType >\n  void apply( const func_t< ValueType >& src, func_t< ValueType >& dst )\n  {\n    std::cout << \"src: \";\n    src.info();\n    std::cout << \"dst: \";\n    dst.info();\n  }\n\n};","metadata":{},"execution_count":6,"outputs":[],"id":"f9b9cb47"},{"cell_type":"code","source":"int main() {\n\n  std::cout << \"\\n-> instantiating oper\" << std::endl;\n  OperatorV2< P1Function > oper;\n\n  std::cout << \"\\n-> applying oper\" << std::endl;\n  P1Function< float > srcP1, dstP1;\n  oper.apply( srcP1, dstP1 );   // instantiates OperatorV2::apply for float\n}\n\nmain();","metadata":{},"execution_count":7,"outputs":[{"name":"stdout","text":"\n-> instantiating oper\naux1: Finite Element Function from P1 Lagrange Space (ValueType = d)\naux2: Finite Element Function from P1 Lagrange Space (ValueType = i)\n\n-> applying oper\nsrc: Finite Element Function from P1 Lagrange Space (ValueType = f)\ndst: Finite Element Function from P1 Lagrange Space (ValueType = f)\n","output_type":"stream"}],"id":"1b69d421"},{"cell_type":"markdown","source":"Note that the example also demonstrates the use of a **template member function**, `OperatorV2::apply()`.\n\n---\nIf we are only interested in retaining the information on the template class, we can also use an approach with two template parameters:","metadata":{},"id":"053c49a5"},{"cell_type":"code","source":"template< template < typename > class func_t, typename value_t >\nclass OperatorV3 {\npublic:\n  OperatorV3() {\n    func_t< value_t > aux1;\n    func_t< int > aux2;\n    std::cout << \"aux1: \"; aux1.info();\n    std::cout << \"aux2: \"; aux2.info();\n  }\n\n  void apply( const func_t< value_t >& src, func_t< value_t >& dst )\n  {\n    std::cout << \"src: \";\n    src.info();\n    std::cout << \"dst: \";\n    dst.info();\n  }\n\n};","metadata":{},"execution_count":8,"outputs":[],"id":"7f98cebb"},{"cell_type":"code","source":"int main() {\n\n  std::cout << \"\\n-> instantiating mass oper\" << std::endl;\n  // OperatorV3< P1Function< float > > mass;\n  OperatorV3< P1Function, float > mass;\n    \n  std::cout << \"\\n-> applying mass oper\" << std::endl;\n  P1Function< float > src, dst;\n  mass.apply( src, dst );\n}\n\nmain();","metadata":{},"execution_count":9,"outputs":[{"name":"stdout","text":"\n-> instantiating mass oper\naux1: Finite Element Function from P1 Lagrange Space (ValueType = f)\naux2: Finite Element Function from P1 Lagrange Space (ValueType = i)\n\n-> applying mass oper\nsrc: Finite Element Function from P1 Lagrange Space (ValueType = f)\ndst: Finite Element Function from P1 Lagrange Space (ValueType = f)\n","output_type":"stream"}],"id":"dd6a1f5d"},{"cell_type":"markdown","source":"## Constexpr If\n\n`if constexpr` was introduced in C++17 and consititutes a form of *conditional compilation* in the context of templates. Let us directly plunge into a first example:","metadata":{},"id":"80018e40-0bbe-4949-b352-f1467e829df9"},{"cell_type":"code","source":"%%file demo.cpp\n\n#include <iostream>\n\nclass A {\npublic:\n  void sayHello() { std::cout << \"Class A says 'Hello'\" << std::endl;\n  }\n};\n\nclass B {\npublic:\n  void gruss() { std::cout << \"Guten Morgen!\" << std::endl;\n  }\n};\n\ntemplate< typename T >\nvoid checkMessage( T& obj ) {\n  if ( std::is_same_v< A, T > ) {\n    obj.sayHello();\n  }\n  else if( std::is_same_v< B, T > ) {\n    obj.gruss();\n  }\n}\n\nint main() {\n  A objTypeA;\n  checkMessage( objTypeA );\n}","metadata":{},"execution_count":10,"outputs":[{"name":"stdout","text":"Writing demo.cpp\n","output_type":"stream"}],"id":"4d05e6d4-b370-40a6-a5ad-334bbe8ed3be"},{"cell_type":"code","source":"!g++ -std=c++17 demo.cpp","metadata":{},"execution_count":11,"outputs":[{"name":"stdout","text":"demo.cpp: In instantiation of ‘void checkMessage(T&) [with T = A]’:\ndemo.cpp:28:26:   required from here\ndemo.cpp:22:9: error: ‘class A’ has no member named ‘gruss’\n     obj.gruss();\n     ~~~~^~~~~\n","output_type":"stream"}],"id":"00c57191-2b46-4181-ad72-4595ac882d03"},{"cell_type":"markdown","source":"The *constexpr if* allows us to resolve this issue:","metadata":{},"id":"451b033c-a240-4b1d-b94b-5b0d7dc75d90"},{"cell_type":"code","source":"%%file demo.cpp\n\n#include <iostream>\n\nclass A {\npublic:\n  void sayHello() { std::cout << \"Class A says 'Hello'\" << std::endl;\n  }\n};\n\nclass B {\npublic:\n  void gruss() { std::cout << \"Guten Morgen!\" << std::endl;\n  }\n};\n\ntemplate< typename T >\nvoid checkMessage( T& obj ) {\n  if constexpr( std::is_same_v< A, T > ) {    // <- here is the important change!\n    obj.sayHello();\n  }\n  else if( std::is_same_v< B, T > ) {\n    obj.gruss();\n    // double a; a->foo();\n  }\n}\n\nint main() {\n  A objTypeA;\n  checkMessage( objTypeA );\n\n  B objTypeB;\n  checkMessage( objTypeB );\n}","metadata":{},"execution_count":12,"outputs":[{"name":"stdout","text":"Overwriting demo.cpp\n","output_type":"stream"}],"id":"6be129fa"},{"cell_type":"code","source":"!g++ -std=c++17 demo.cpp","metadata":{},"execution_count":13,"outputs":[],"id":"1ac9c0ba"},{"cell_type":"code","source":"!./a.out","metadata":{},"execution_count":14,"outputs":[{"name":"stdout","text":"Class A says 'Hello'\nGuten Morgen!\n","output_type":"stream"}],"id":"083cc1e4"},{"cell_type":"markdown","source":"What is the difference?\n\nThe condition in an *constexpr if* must be in general be a <a href=\"https://en.cppreference.com/w/cpp/language/constant_expression#Converted_constant_expression\">contextually converted constant expression of type bool</a>.\n\nIn our template example it is something the compiler can check at instantiation! In this case the branch for which condition evaluates to *true* is instantiated, the other not! This is what makes the difference.\n\nNote that the *false* branch, while not being instantiated, must still be syntactically correct. Remember the **two-phase lookup** we discussed. Not being instantiated means the second phase is skipped, but the code still needs to pass the first phase!\n\nThus, this is not equivalent to conditional compilation with preprocessing directives. As can be seen from the following example from cppreference.com:","metadata":{},"id":"c99ff76a"},{"cell_type":"code","source":"void f() {\n    if constexpr(false) {\n        int i = 0;\n        int *p = i; // Error even though in discarded statement\n    }\n}","metadata":{},"execution_count":15,"outputs":[{"name":"stderr","text":"input_line_15:4:14: error: cannot initialize a variable of type 'int *' with an lvalue of type 'int'\n        int *p = i; // Error even though in discarded statement\n             ^   ~\n","output_type":"stream"},{"ename":"Interpreter Error","evalue":"","traceback":["Interpreter Error: "],"output_type":"error"}],"id":"ed62c962"},{"cell_type":"markdown","source":"---\nA maybe more realistic example for the use of *constexpr if* is the following from the <a href=\"https://blog.tartanllama.xyz/if-constexpr/\">blog</a> by Sy Brand. Note that this also features automatic return type deduction:","metadata":{},"id":"bd46e337"},{"cell_type":"code","source":"#include <type_traits>\n\ntemplate <typename T>\nauto get_value(T t) {\n    if constexpr (std::is_pointer_v<T>)\n        return *t;\n    else\n        return t;\n}","metadata":{},"execution_count":16,"outputs":[],"id":"c273e25c-652a-461d-b351-3123afccbc11"},{"cell_type":"markdown","source":"Now let us test-drive this:","metadata":{},"id":"3c1ba823-1b7e-4d7e-be29-59b0c1782579"},{"cell_type":"code","source":"#include <iostream>\n\nint main() {\n\n  int  a = 2;\n  int* p = &a;\n\n  std::cout << \"direct access ..... a = \" << get_value( a ) << std::endl;\n  std::cout << \"indirect access ... a = \" << get_value( p ) << std::endl;\n\n}\n\nmain();","metadata":{},"execution_count":17,"outputs":[{"name":"stdout","text":"direct access ..... a = 2\nindirect access ... a = 2\n","output_type":"stream"}],"id":"df64d78d-eecb-408d-a9db-1b1a72716de2"},{"cell_type":"markdown","source":"When we inspect the instantiations with <a href=\"https://cppinsights.io/\">cppinsights</a> we see that indeed only the valid branch gets instantiated:\n<center><img src=\"../images/cppInsights02.png\" width=\"70%\"></center>","metadata":{},"id":"25c99ad6"},{"cell_type":"markdown","source":"The *constexpr if* allows to simplify templates by reducing the need for specialisations, like in the following example using template meta-programming:","metadata":{},"id":"396d5d0e"},{"cell_type":"code","source":"%%file power.cpp\n\n#define CONST_EXPR\n\n#ifndef CONST_EXPR\n\ntemplate< int base, unsigned int exp >\nstruct Power {\n  static int value() {\n    return base * Power< base, exp - 1u >::value();\n  }\n};\n\ntemplate< int base >\nstruct Power< base, 0 > {\n  static int value() {\n    return 1;\n  }\n};\n\n#else\n\ntemplate< int base, unsigned int exp >\nstruct Power {\n  static int value() {\n    if constexpr( exp > 0 ) {\n      return base * Power< base, exp - 1u >::value();\n    }\n    else {\n      return 1;\n    }\n  }\n};\n\n#endif\n\n#include <iostream>\n\nint main() {\n  std::cout << \"5^3 = \" << Power<5,3>::value() << std::endl;\n}","metadata":{"scrolled":true,"tags":[]},"execution_count":22,"outputs":[{"name":"stdout","text":"Overwriting power.cpp\n","output_type":"stream"}],"id":"4f01ee73"},{"cell_type":"code","source":"!g++ -std=c++17 power.cpp","metadata":{},"execution_count":23,"outputs":[],"id":"8a4bb240"},{"cell_type":"code","source":"!./a.out","metadata":{},"execution_count":24,"outputs":[{"name":"stdout","text":"5^3 = 125\n","output_type":"stream"}],"id":"39268b6a"},{"cell_type":"markdown","source":"## Dependent Names Revisited\nWe had encountered the concept of *non-dependent* and <a href=\"https://en.cppreference.com/w/cpp/language/dependent_name\">*dependent names*</a> in notebook # 12, when we looked at inheritance of template classes and their member functions.\n\nIn the context of dependent names the following keywords might be needed:\n* `typename`\n* `template`\n\nAssume we have the following template class:","metadata":{},"id":"b52ae491"},{"cell_type":"code","source":"template< typename T >\nclass A {\npublic:\n    using ptrType = T*;\n};","metadata":{},"execution_count":25,"outputs":[],"id":"8995872a"},{"cell_type":"markdown","source":"Now we write a template function that internally needs to generate a pointer ","metadata":{},"id":"60809792"},{"cell_type":"code","source":"template< typename T >\nvoid doSomething( T& obj ) {\n    A<T>::ptrType valPtr;\n}","metadata":{},"execution_count":26,"outputs":[{"name":"stderr","text":"input_line_21:3:18: error: expected ';' after expression\n    A<T>::ptrType valPtr;\n                 ^\n                 ;\ninput_line_21:3:19: error: use of undeclared identifier 'valPtr'\n    A<T>::ptrType valPtr;\n                  ^\n","output_type":"stream"},{"ename":"Interpreter Error","evalue":"","traceback":["Interpreter Error: "],"output_type":"error"}],"id":"f19c19b9"},{"cell_type":"markdown","source":"Hmm, what is the problem here? Let's try something else:","metadata":{},"id":"fef65d8e"},{"cell_type":"code","source":"template< typename T >\nclass foo {\n  using vType = T::valueType;\n};","metadata":{},"execution_count":27,"outputs":[{"name":"stderr","text":"input_line_22:3:17: error: missing 'typename' prior to dependent type name 'T::valueType'\n  using vType = T::valueType;\n                ^~~~~~~~~~~~\n                typename \n","output_type":"stream"},{"ename":"Interpreter Error","evalue":"","traceback":["Interpreter Error: "],"output_type":"error"}],"id":"975025b2"},{"cell_type":"markdown","source":"In both cases we use a name that is dependent on the template parameter `T`\n* `A<T>::ptrType`\n* `T::valueType`\n\nThe full details of this are tricky, but basically we need to help the compiler to understand that we are using a type name, by using the `typename` keyword.\n\nFrom cppreference.com:\n> In a declaration or a definition of a template, including alias template, a name that is not a member of the current instantiation and is dependent on a template parameter is not considered to be a type unless the keyword typename is used or unless it was already established as a type name, e.g. with a typedef declaration or by being used to name a base class.\n\nThat explains the error messages from the first example. `A<T>::ptrType` is not seen as a type name, but treated as a member of the template class `A<T>`.\n\nIndeed, adding the `typename` keyword fixes the problem:","metadata":{},"id":"fc965154"},{"cell_type":"code","source":"template< typename T >\nvoid doSomething( T& obj ) {\n    typename A<T>::ptrType valPtr;\n}","metadata":{},"execution_count":28,"outputs":[],"id":"afb191b0"},{"cell_type":"markdown","source":"A similar ambiguity problem can occur with template names:\n\n> Similarly, in a template definition, a dependent name that is not a member of the current instantiation is not considered to be a template name unless the disambiguation keyword template is used or unless it was already established as a template name.\n\nAssume we have class with a templated member function\n```c++\nclass B {\npublic:\n    template< typename T >\n    void run() {};\n};\n```\nNow we write a template function that internally generates an object, its type being the template parameter `T`, and calls its templated `run()`member function.","metadata":{},"id":"12c0fa43"},{"cell_type":"code","source":"template< typename T >\nvoid func() {\n  T obj;\n  obj.run< T >();\n}","metadata":{"scrolled":true},"execution_count":29,"outputs":[{"name":"stderr","text":"input_line_24:4:7: error: use 'template' keyword to treat 'run' as a dependent template name\n  obj.run< T >();\n      ^\n      template \n","output_type":"stream"},{"ename":"Interpreter Error","evalue":"","traceback":["Interpreter Error: "],"output_type":"error"}],"id":"695e3775"},{"cell_type":"code","source":"template< typename T >\nvoid func() {\n  T obj;\n  obj.template run< T >();\n}","metadata":{},"execution_count":30,"outputs":[],"id":"da772d07"},{"cell_type":"markdown","source":"## CRTP: Curiously Recurring Template Pattern","metadata":{},"id":"bb14f831"},{"cell_type":"markdown","source":"The curiously recurring template patterns describes a technique, where a class B inherits from a template class A, using itself as template argument:\n\n```c++\ntemplate< typename T >\nclass A {};\n\nclass B : public A< B > {};\n```\nA nice list of usage scenarios and examples for CRTP can be found on the webpages of <a href=\"http://www.vishalchovatiya.com/crtp-c-examples/\">Vishal Chovatiya</a>. The first of these demonstrates static polymorphism:","metadata":{},"id":"0af04dfc"},{"cell_type":"code","source":"%%file crtp.cpp\n\n#include <iostream>\n\ntemplate<typename specific_animal>\nstruct animal {\n    void who() { static_cast<specific_animal*>(this)->who(); }\n};\n\nstruct dog : animal<dog> {\n    void who() { std::cout << \"dog\" << std::endl; }\n};\n\nstruct cat : animal<cat> {\n    void who() { std::cout << \"cat\" << std::endl; }\n};\n\ntemplate<typename specific_animal>\nvoid who_am_i(animal<specific_animal> &animal) {\n    animal.who();\n}\n\nint main( void ) {\n\n  cat c;\n  who_am_i(c); // prints `cat`\n\n  dog d;\n  who_am_i(d); // prints `dog`\n\n}\n","metadata":{},"execution_count":31,"outputs":[{"name":"stdout","text":"Writing crtp.cpp\n","output_type":"stream"}],"id":"fffce178"},{"cell_type":"code","source":"!g++ crtp.cpp","metadata":{},"execution_count":32,"outputs":[],"id":"1e32d10d"},{"cell_type":"code","source":"!./a.out","metadata":{},"execution_count":33,"outputs":[{"name":"stdout","text":"cat\ndog\n","output_type":"stream"}],"id":"da65a685"},{"cell_type":"markdown","source":"The catch here is that the `animal` class delegates the actual implementation of the `who()` member function to its children. However, in contrast to dynamic polymorphism with virtual functions this is handled at compile-time and does not induces a run-time penalty.","metadata":{},"id":"3d5e5fae"},{"cell_type":"markdown","source":"The final object counter example is taken from <a href=\"https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern#Object_counter\">Wikipedia</a>: ","metadata":{},"id":"34f3bf32"},{"cell_type":"code","source":"#include <iostream>\n\ntemplate <typename T>\nstruct counter\n{\n  static inline int objects_created = 0;\n  static inline int objects_alive = 0;\n\n  counter()\n  {\n    ++objects_created;\n    ++objects_alive;\n  }\n    \n  counter(const counter&)\n  {\n    ++objects_created;\n    ++objects_alive;\n  }\nprotected:\n  ~counter() // objects should never be removed through pointers of this type\n  {\n    --objects_alive;\n  }\n};\n\nclass X : counter<X>\n{\n  // ...\n};\n\nclass Y : counter<Y>\n{\n  // ...\n};\n\n\nint main() {\n\n  Y objY;\n  for( int k = 0; k < 2; ++k ) {\n    X* ptr = new X;\n    Y v;\n  }\n\n  std::cout << \"X created: \" << counter<X>::objects_created << std::endl;\n  std::cout << \"X alive:   \" << counter<X>::objects_alive << std::endl;\n\n  std::cout << \"Y created: \" << counter<Y>::objects_created << std::endl;\n  std::cout << \"Y alive:   \" << counter<Y>::objects_alive << std::endl;\n}","metadata":{},"execution_count":34,"outputs":[],"id":"fcf8be3c"},{"cell_type":"markdown","source":"What will this print?","metadata":{},"id":"f3309e3c"},{"cell_type":"code","source":"main();","metadata":{},"execution_count":35,"outputs":[{"name":"stdout","text":"X created: 2\nX alive:   2\nY created: 3\nY alive:   1\n","output_type":"stream"}],"id":"d761dd85"},{"cell_type":"markdown","source":"Note that the templatisation of the `counter` class is essential here, as this will give us one individual counter pair per child `X` and `Y`.","metadata":{},"id":"1aa4f375-6b97-4009-a3c4-82aa59a8b60f"},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[],"id":"22449331-1de2-48f1-82cf-bd5666124408"}]}
\ No newline at end of file
diff --git a/notebooks/16_MultipleDispatch.ipynb b/notebooks/16_MultipleDispatch.ipynb
index a5d0b1edcc0e89f908d6561d4b413b7e63ee154e..b4630d4e34df4b34060bce39205a8f4c0f44e5f4 100644
--- a/notebooks/16_MultipleDispatch.ipynb
+++ b/notebooks/16_MultipleDispatch.ipynb
@@ -1 +1 @@
-{"metadata":{"language_info":{"codemirror_mode":"text/x-c++src","file_extension":".cpp","mimetype":"text/x-c++src","name":"c++","version":"17"},"kernelspec":{"name":"xcpp17","display_name":"C++17","language":"C++17"}},"nbformat_minor":5,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Multiple Dispatch\n\nIn his [Geocomputing presentation](https://www.geophysik.uni-muenchen.de/en/seminars/seminars/geocomputing-29/t-b-a-6) Roman Freissler mentioned **multiple dispatch** as one of the features of the programming language **Julia**. So what is it?\n\n### Wikipedia:\n> Multiple dispatch or multimethods is a feature of some programming languages in which a function or method can be dynamically dispatched based on the run-time (dynamic) type or, in the more general case, some other attribute of more than one of its arguments.[1] This is a generalization of single-dispatch polymorphism where a function or method call is dynamically dispatched based on the derived type of the object on which the method has been called. Multiple dispatch routes the dynamic dispatch to the implementing function or method using the combined characteristics of one or more arguments.\n\n```\nabstract type SpaceObject end\n\nstruct Asteroid <: SpaceObject\n    size::Int    \nend\nstruct Spaceship <: SpaceObject\n    size::Int                  \nend              \n\ncollide_with(::Asteroid, ::Spaceship) = \"a/s\"\ncollide_with(::Spaceship, ::Asteroid) = \"s/a\"\ncollide_with(::Spaceship, ::Spaceship) = \"s/s\"\ncollide_with(::Asteroid, ::Asteroid) = \"a/a\"\n\ncollide(x::SpaceObject, y::SpaceObject) = (x.size > 100 && y.size > 100) ? \"Big boom!\" : collide_with(x, y)\n\n\njulia> collide(Asteroid(101), Spaceship(300))\n\"Big boom!\"\n\njulia> collide(Asteroid(10), Spaceship(10))\n\"a/s\"\n\njulia> collide(Spaceship(101), Spaceship(10))\n\"s/s\"\n```\n","metadata":{},"id":"559dbab5-4930-41cf-ab02-99ed7e282149"},{"cell_type":"markdown","source":"## C++\nC++ does support *dynamic dispatch*, but only in the form of *single dispatch*. Consider the following example:","metadata":{},"id":"58bd10b2-159d-473b-962d-3b09fd7437cd"},{"cell_type":"code","source":"#include <iostream>\n\nstruct Animal {\n    virtual void makeSound() const = 0;\n};\n\nstruct Cat : public Animal {\n    void makeSound() const override {\n        std::cout << \"Meow\" << std::endl;\n    }\n};\n\nstruct Dog : public Animal {\n    void makeSound() const override {\n        std::cout << \"Wuff\" << std::endl;\n    }\n};","metadata":{},"execution_count":3,"outputs":[],"id":"c5d388d8-79d7-49d7-a37c-4805521920a1"},{"cell_type":"code","source":"int main() {\n    Cat boss;\n    Dog partner;\n    Animal* animal1{ &boss };\n    Animal* animal2{ &partner };\n    animal1->makeSound();\n    animal2->makeSound();\n}\n\nmain();","metadata":{},"execution_count":10,"outputs":[{"name":"stdout","text":"Meow\nWuff\n","output_type":"stream"}],"id":"bf13fc00-47e6-449c-af3d-4f45f84559ac"},{"cell_type":"markdown","source":"The decision which member function `makeSound` is to be called is taken at runtime depending on the type of child object of `Animal` the pointer points to. Conceptually this happens by examining the first *hidden argument* of `makeSound( this, ... )`.\n\nWhile C++ does **not support multiple dispatch**, we can emulate it in various ways (examples modified from Wikipedia).\n\n#### Multiple Dispatch via Dynamic Casting","metadata":{},"id":"18e383f7-a368-42f9-b398-c4a8d13fc175"},{"cell_type":"code","source":"%%file md_with_casting.cpp\n\n#include <iostream>\n\nstruct SpaceObject {\n  SpaceObject( int in ) : size(in) {};\n  virtual void collideWith( SpaceObject& other ) = 0;\n  int size;\n};\n\n// Need to split class declaration and method implementation\n// because we can only cast complete types, thus, a forward\n// declaration is not sufficient.\nstruct Asteroid : SpaceObject {\n  Asteroid( int in ) : SpaceObject( in ) {};\n  void collideWith( SpaceObject& other );\n};\n\nstruct Spaceship : SpaceObject {\n  Spaceship( int in ) : SpaceObject( in ) {};\n  void collideWith( SpaceObject& other );\n};\n\nvoid Asteroid::collideWith( SpaceObject& other ) {\n\n  // dynamic_cast to a pointer type returns NULL if the cast fails\n  // (dynamic_cast to a reference type would throw an exception on failure)\n\n  if( auto asteroid = dynamic_cast< Asteroid* >( &other ) ) {\n\n    // handle Asteroid-Asteroid collision\n    std::cout << \"Asteroid-Asteroid collision!\" << std::endl;\n\n  } else if( auto spaceship = dynamic_cast< Spaceship* >( &other ) ) {\n\n    // handle Asteroid-Spaceship collision\n    std::cout << \"Asteroid-Spaceship collision!\" << std::endl;\n\n  } else {\n\n    // default collision handling here\n    std::cout << \"Asteroid-UFO collision!\" << std::endl;\n\n  }\n}\n\nvoid Spaceship::collideWith( SpaceObject& other ) {\n\n  if( auto asteroid = dynamic_cast< Asteroid* >( &other ) ) {\n\n    // handle Spaceship-Asteroid collision\n    std::cout << \"Spaceship-Asteroid collision!\" << std::endl;\n\n  } else if( auto spaceship = dynamic_cast< Spaceship* >( &other ) ) {\n\n    // handle Spaceship-Spaceship collision\n    std::cout << \"Spaceship-Spaceship collision!\" << std::endl;\n\n  } else {\n\n    // default collision handling here\n    std::cout << \"Spaceship-UFO collision!\" << std::endl;\n\n  }\n}\n\nvoid collide( SpaceObject& x, SpaceObject& y ) {\n  if( x.size > 100 && y.size > 100 ) {\n    std::cout << \"Big boom!\" << std::endl;\n  }\n  else {\n    x.collideWith( y );\n  }\n}\n\nint main() {\n  Asteroid asteroid{101};\n  Spaceship spaceship{300};\n\n  collide( asteroid, spaceship );\n\n  asteroid.size = 10;\n  spaceship.size = 10;\n  collide( asteroid, spaceship );\n  collide( asteroid, asteroid );\n  collide( spaceship, asteroid );\n  collide( spaceship, spaceship );\n}","metadata":{"trusted":true},"execution_count":1,"outputs":[{"name":"stdout","text":"Writing md_with_casting.cpp\n","output_type":"stream"}],"id":"abec11bc-6cc1-4100-a2df-0e308ffc71ed"},{"cell_type":"code","source":"!g++ md_with_casting.cpp","metadata":{"trusted":true},"execution_count":2,"outputs":[],"id":"547cb38a-82e2-4f62-9b6e-23d5462087e6"},{"cell_type":"code","source":"!./a.out","metadata":{"trusted":true},"execution_count":3,"outputs":[{"name":"stdout","text":"Big boom!\nAsteroid-Spaceship collision!\nAsteroid-Asteroid collision!\nSpaceship-Asteroid collision!\nSpaceship-Spaceship collision!\n","output_type":"stream"}],"id":"b60b5e86-e09b-4e48-938d-956626d6b5c9"},{"cell_type":"markdown","source":"#### Multiple Dispatch via Map","metadata":{},"id":"bc7899b8-32f8-4c31-bc5b-7c7f5f43fe49"},{"cell_type":"code","source":"%%file md_with_map.cpp\n#include <cstdint>\n#include <typeinfo>\n#include <unordered_map>\n#include <iostream>\n\nclass Thing {\n\nprotected:\n\n  Thing( std::uint32_t cid ) : tid( cid ) {}\n\n  const std::uint32_t tid; // type id\n\n  using CollisionHandler = void(Thing::*)(Thing& other);\n  using CollisionHandlerMap = std::unordered_map< std::uint64_t, CollisionHandler >;\n\n    static void addHandler( std::uint32_t id1, std::uint32_t id2, CollisionHandler handler ) {\n        collisionCases.insert( CollisionHandlerMap::value_type( key( id1, id2 ), handler ) );\n    }\n\n    static std::uint64_t key( std::uint32_t id1, std::uint32_t id2 ) {\n        return std::uint64_t(id1) << 32 | id2;\n    }\n\n    static CollisionHandlerMap collisionCases;\n\n  public:\n    void collideWith( Thing& other ) {\n        auto handler = collisionCases.find( key( tid, other.tid ) );\n        if ( handler != collisionCases.end() ) {\n          ( this->*(handler->second) )( other ); // pointer-to-method call\n          // ( this->*handler->second )( other ); // pointer-to-method call\n        } else {\n           std::cout << \"Collision of unknown type!\" << std::endl;\n        }\n    }\n};\n\nclass Asteroid: public Thing {\n\n    void asteroid_collision( Thing& other )   {\n      std::cout << \"Asteroid-Asteroid collision!\" << std::endl;\n    }\n\n    void spaceship_collision( Thing& other )  {\n      std::cout << \"Asteroid-Spaceship collision!\" << std::endl;\n    }\n\n  public:\n\n    Asteroid(): Thing( cid ) {}\n    static void initCases();\n    static const std::uint32_t cid;\n\n};\n\nclass Spaceship: public Thing {\n\n    void asteroid_collision( Thing& other ) {\n      std::cout << \"Spaceship-Asteroid collision!\" << std::endl;\n    }\n\n    void spaceship_collision( Thing& other ) {\n      std::cout << \"Spaceship-Spaceship collision!\" << std::endl;\n    }\n\n\n  public:\n\n    Spaceship(): Thing( cid ) {}\n    static void initCases();\n    static const std::uint32_t cid; // class id\n\n};\n\nThing::CollisionHandlerMap Thing::collisionCases;\nconst std::uint32_t Asteroid::cid = typeid( Asteroid ).hash_code();\nconst std::uint32_t Spaceship::cid = typeid( Spaceship ).hash_code();\n\nvoid Asteroid::initCases() {\n    addHandler( cid, cid, CollisionHandler(&Asteroid::asteroid_collision ) );\n    addHandler( cid, Spaceship::cid, CollisionHandler(&Asteroid::spaceship_collision ) );\n}\n\nvoid Spaceship::initCases() {\n    addHandler( cid, Asteroid::cid, CollisionHandler( &Spaceship::asteroid_collision ) );\n    addHandler( cid, cid, CollisionHandler( &Spaceship::spaceship_collision ) );\n}\n\nint main() {\n    Asteroid::initCases();\n    Spaceship::initCases();\n\n    Asteroid  a1, a2;\n    Spaceship s1, s2;\n\n    a1.collideWith( a2 );\n    a1.collideWith( s1 );\n\n    s1.collideWith( s2 );\n    s1.collideWith( a1 );\n}","metadata":{"trusted":true},"execution_count":5,"outputs":[{"name":"stdout","text":"Writing md_with_map.cpp\n","output_type":"stream"}],"id":"00f07cb8-9b9f-49f9-aaa4-251edbedf7a6"},{"cell_type":"code","source":"!g++ md_with_map.cpp","metadata":{"trusted":true},"execution_count":6,"outputs":[],"id":"add9aaee-5fac-4206-8d00-de314f99631e"},{"cell_type":"code","source":"!./a.out","metadata":{"trusted":true},"execution_count":7,"outputs":[{"name":"stdout","text":"Asteroid-Asteroid collision!\nAsteroid-Spaceship collision!\nSpaceship-Spaceship collision!\nSpaceship-Asteroid collision!\n","output_type":"stream"}],"id":"1092b652-e9df-4b12-9295-82fff8923817"},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[],"id":"24efc2a0-8297-489d-abd1-d76abb15711c"}]}
\ No newline at end of file
+{"metadata":{"kernelspec":{"display_name":"C++17","language":"C++17","name":"xcpp17"},"language_info":{"codemirror_mode":"text/x-c++src","file_extension":".cpp","mimetype":"text/x-c++src","name":"c++","version":"17"}},"nbformat_minor":5,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Multiple Dispatch\n\nIn his [Geocomputing presentation](https://www.geophysik.uni-muenchen.de/en/seminars/seminars/geocomputing-29/t-b-a-6) Roman Freissler mentioned **multiple dispatch** as one of the features of the programming language **Julia**. So what is it?\n\n### Wikipedia:\n> Multiple dispatch or multimethods is a feature of some programming languages in which a function or method can be dynamically dispatched based on the run-time (dynamic) type or, in the more general case, some other attribute of more than one of its arguments.[1] This is a generalization of single-dispatch polymorphism where a function or method call is dynamically dispatched based on the derived type of the object on which the method has been called. Multiple dispatch routes the dynamic dispatch to the implementing function or method using the combined characteristics of one or more arguments.\n\n```\nabstract type SpaceObject end\n\nstruct Asteroid <: SpaceObject\n    size::Int    \nend\nstruct Spaceship <: SpaceObject\n    size::Int                  \nend              \n\ncollide_with(::Asteroid, ::Spaceship) = \"a/s\"\ncollide_with(::Spaceship, ::Asteroid) = \"s/a\"\ncollide_with(::Spaceship, ::Spaceship) = \"s/s\"\ncollide_with(::Asteroid, ::Asteroid) = \"a/a\"\n\ncollide(x::SpaceObject, y::SpaceObject) = (x.size > 100 && y.size > 100) ? \"Big boom!\" : collide_with(x, y)\n\n\njulia> collide(Asteroid(101), Spaceship(300))\n\"Big boom!\"\n\njulia> collide(Asteroid(10), Spaceship(10))\n\"a/s\"\n\njulia> collide(Spaceship(101), Spaceship(10))\n\"s/s\"\n```\n","metadata":{},"id":"559dbab5-4930-41cf-ab02-99ed7e282149"},{"cell_type":"markdown","source":"## C++\nC++ does support *dynamic dispatch*, but only in the form of *single dispatch*. Consider the following example:","metadata":{},"id":"58bd10b2-159d-473b-962d-3b09fd7437cd"},{"cell_type":"code","source":"#include <iostream>\n\nstruct Animal {\n    virtual void makeSound() const = 0;\n};\n\nstruct Cat : public Animal {\n    void makeSound() const override {\n        std::cout << \"Meow\" << std::endl;\n    }\n};\n\nstruct Dog : public Animal {\n    void makeSound() const override {\n        std::cout << \"Wuff\" << std::endl;\n    }\n};","metadata":{"trusted":true},"execution_count":3,"outputs":[],"id":"c5d388d8-79d7-49d7-a37c-4805521920a1"},{"cell_type":"code","source":"int main() {\n    Cat boss;\n    Dog partner;\n    Animal* animal1{ &boss };\n    Animal* animal2{ &partner };\n    animal1->makeSound();\n    animal2->makeSound();\n}\n\nmain();","metadata":{"trusted":true},"execution_count":10,"outputs":[{"name":"stdout","output_type":"stream","text":"Meow\nWuff\n"}],"id":"bf13fc00-47e6-449c-af3d-4f45f84559ac"},{"cell_type":"markdown","source":"The decision which member function `makeSound` is to be called is taken at runtime depending on the type of child object of `Animal` the pointer points to. Conceptually this happens by examining the first *hidden argument* of `makeSound( this, ... )`. [Note: Compare this 'classic' implementation to the CRTP version in notebook # 13]\n\nWhile C++ does **not support multiple dispatch**, we can emulate it in various ways (examples modified from Wikipedia).\n\n#### Multiple Dispatch via Dynamic Casting","metadata":{},"id":"18e383f7-a368-42f9-b398-c4a8d13fc175"},{"cell_type":"code","source":"%%file md_with_casting.cpp\n\n#include <iostream>\n\nstruct SpaceObject {\n  SpaceObject( int in ) : size(in) {};\n  virtual void collideWith( SpaceObject& other ) = 0;\n  int size;\n};\n\n// Need to split class declaration and method implementation\n// because we can only cast complete types, thus, a forward\n// declaration is not sufficient.\nstruct Asteroid : SpaceObject {\n  Asteroid( int in ) : SpaceObject( in ) {};\n  void collideWith( SpaceObject& other );\n};\n\nstruct Spaceship : SpaceObject {\n  Spaceship( int in ) : SpaceObject( in ) {};\n  void collideWith( SpaceObject& other );\n};\n\nvoid Asteroid::collideWith( SpaceObject& other ) {\n\n  // dynamic_cast to a pointer type returns NULL if the cast fails\n  // (dynamic_cast to a reference type would throw an exception on failure)\n\n  if( auto asteroid = dynamic_cast< Asteroid* >( &other ) ) {\n\n    // handle Asteroid-Asteroid collision\n    std::cout << \"Asteroid-Asteroid collision!\" << std::endl;\n\n  } else if( auto spaceship = dynamic_cast< Spaceship* >( &other ) ) {\n\n    // handle Asteroid-Spaceship collision\n    std::cout << \"Asteroid-Spaceship collision!\" << std::endl;\n\n  } else {\n\n    // default collision handling here\n    std::cout << \"Asteroid-UFO collision!\" << std::endl;\n\n  }\n}\n\nvoid Spaceship::collideWith( SpaceObject& other ) {\n\n  if( auto asteroid = dynamic_cast< Asteroid* >( &other ) ) {\n\n    // handle Spaceship-Asteroid collision\n    std::cout << \"Spaceship-Asteroid collision!\" << std::endl;\n\n  } else if( auto spaceship = dynamic_cast< Spaceship* >( &other ) ) {\n\n    // handle Spaceship-Spaceship collision\n    std::cout << \"Spaceship-Spaceship collision!\" << std::endl;\n\n  } else {\n\n    // default collision handling here\n    std::cout << \"Spaceship-UFO collision!\" << std::endl;\n\n  }\n}\n\nvoid collide( SpaceObject& x, SpaceObject& y ) {\n  if( x.size > 100 && y.size > 100 ) {\n    std::cout << \"Big boom!\" << std::endl;\n  }\n  else {\n    x.collideWith( y );\n  }\n}\n\nint main() {\n  Asteroid asteroid{101};\n  Spaceship spaceship{300};\n\n  collide( asteroid, spaceship );\n\n  asteroid.size = 10;\n  spaceship.size = 10;\n  collide( asteroid, spaceship );\n  collide( asteroid, asteroid );\n  collide( spaceship, asteroid );\n  collide( spaceship, spaceship );\n}","metadata":{"trusted":true},"execution_count":1,"outputs":[{"name":"stdout","output_type":"stream","text":"Writing md_with_casting.cpp\n"}],"id":"abec11bc-6cc1-4100-a2df-0e308ffc71ed"},{"cell_type":"code","source":"!g++ md_with_casting.cpp","metadata":{"trusted":true},"execution_count":2,"outputs":[],"id":"547cb38a-82e2-4f62-9b6e-23d5462087e6"},{"cell_type":"code","source":"!./a.out","metadata":{"trusted":true},"execution_count":3,"outputs":[{"name":"stdout","output_type":"stream","text":"Big boom!\nAsteroid-Spaceship collision!\nAsteroid-Asteroid collision!\nSpaceship-Asteroid collision!\nSpaceship-Spaceship collision!\n"}],"id":"b60b5e86-e09b-4e48-938d-956626d6b5c9"},{"cell_type":"markdown","source":"#### Multiple Dispatch via Map","metadata":{},"id":"bc7899b8-32f8-4c31-bc5b-7c7f5f43fe49"},{"cell_type":"code","source":"%%file md_with_map.cpp\n#include <cstdint>\n#include <typeinfo>\n#include <unordered_map>\n#include <iostream>\n\nclass Thing {\n\nprotected:\n\n  Thing( std::uint32_t cid ) : tid( cid ) {}\n\n  const std::uint32_t tid; // type id\n\n  // type alias for function pointer to member function handling collision event\n  using CollisionHandler = void(Thing::*)(Thing& other);\n  \n  // type alias for the map we are using\n  using CollisionHandlerMap = std::unordered_map< std::uint64_t, CollisionHandler >;\n\n  // method for inserting a collision handling function into the map \n  static void addHandler( std::uint32_t id1, std::uint32_t id2, CollisionHandler handler ) {\n    collisionCases.insert( CollisionHandlerMap::value_type( key( id1, id2 ), handler ) );\n  }\n\n  // combine the two type ids of the objects involved in the collision into a single key\n  static std::uint64_t key( std::uint32_t id1, std::uint32_t id2 ) {\n    return std::uint64_t( id1 ) << 32 | std::uint64_t( id2 );\n  }\n\n  // the central map object for handling the multiple dispatch\n  static CollisionHandlerMap collisionCases;\n\n  public:\n  \n    // member function for performing the dispatch\n    void collideWith( Thing& other ) {\n        auto handler = collisionCases.find( key( tid, other.tid ) );\n        if ( handler != collisionCases.end() ) {\n          ( this->*(handler->second) )( other ); // pointer-to-method call\n          // ( this->*handler->second )( other ); // pointer-to-method call\n        } else {\n           std::cout << \"Collision of unknown type!\" << std::endl;\n        }\n    }\n};\n\nclass Asteroid: public Thing {\n\n    void asteroid_collision( Thing& other )   {\n      std::cout << \"Asteroid-Asteroid collision!\" << std::endl;\n    }\n\n    void spaceship_collision( Thing& other )  {\n      std::cout << \"Asteroid-Spaceship collision!\" << std::endl;\n    }\n\n  public:\n\n    Asteroid(): Thing( cid ) {}\n    static void initCases();\n    static const std::uint32_t cid;\n\n};\n\nclass Spaceship: public Thing {\n\n    void asteroid_collision( Thing& other ) {\n      std::cout << \"Spaceship-Asteroid collision!\" << std::endl;\n    }\n\n    void spaceship_collision( Thing& other ) {\n      std::cout << \"Spaceship-Spaceship collision!\" << std::endl;\n    }\n\n\n  public:\n\n    Spaceship(): Thing( cid ) {}\n    static void initCases();\n    static const std::uint32_t cid; // class id\n\n};\n\n// initialisation of some static data members\nThing::CollisionHandlerMap Thing::collisionCases;\nconst std::uint32_t Asteroid::cid = typeid( Asteroid ).hash_code();\nconst std::uint32_t Spaceship::cid = typeid( Spaceship ).hash_code();\n\nvoid Asteroid::initCases() {\n    addHandler( cid, cid, CollisionHandler(&Asteroid::asteroid_collision ) );\n    addHandler( cid, Spaceship::cid, CollisionHandler(&Asteroid::spaceship_collision ) );\n}\n\nvoid Spaceship::initCases() {\n    addHandler( cid, Asteroid::cid, CollisionHandler( &Spaceship::asteroid_collision ) );\n    addHandler( cid, cid, CollisionHandler( &Spaceship::spaceship_collision ) );\n}\n\nint main() {\n    Asteroid::initCases();\n    Spaceship::initCases();\n\n    Asteroid  a1, a2;\n    Spaceship s1, s2;\n\n    a1.collideWith( a2 );\n    a1.collideWith( s1 );\n\n    s1.collideWith( s2 );\n    s1.collideWith( a1 );\n}","metadata":{"trusted":true},"execution_count":17,"outputs":[{"name":"stdout","text":"Overwriting md_with_map.cpp\n","output_type":"stream"}],"id":"00f07cb8-9b9f-49f9-aaa4-251edbedf7a6"},{"cell_type":"code","source":"!g++ md_with_map.cpp","metadata":{"trusted":true},"execution_count":18,"outputs":[],"id":"add9aaee-5fac-4206-8d00-de314f99631e"},{"cell_type":"code","source":"!./a.out","metadata":{"trusted":true},"execution_count":19,"outputs":[{"name":"stdout","text":"Asteroid-Asteroid collision!\nAsteroid-Spaceship collision!\nSpaceship-Spaceship collision!\nSpaceship-Asteroid collision!\n","output_type":"stream"}],"id":"1092b652-e9df-4b12-9295-82fff8923817"},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[],"id":"24efc2a0-8297-489d-abd1-d76abb15711c"}]}
\ No newline at end of file