From 8d3011d366f3b40a70fc719d969630799b0608bb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Gilles?= <sebastien.gilles@inria.fr>
Date: Sun, 2 May 2021 10:31:35 +0200
Subject: [PATCH 1/2] Create a new notebook in procedural to discuss static and
 constexpr. The static part was lifted from the notebook in ibject programming
 in which it was originally introduced.

---
 1-ProceduralProgramming/0-main.ipynb          |   3 +-
 .../7-StaticAndConstexpr.ipynb                | 304 ++++++++++++++++++
 2-ObjectProgramming/5-static.ipynb            |  71 +---
 3 files changed, 308 insertions(+), 70 deletions(-)
 create mode 100644 1-ProceduralProgramming/7-StaticAndConstexpr.ipynb

diff --git a/1-ProceduralProgramming/0-main.ipynb b/1-ProceduralProgramming/0-main.ipynb
index 6cbe872..003c9ef 100644
--- a/1-ProceduralProgramming/0-main.ipynb
+++ b/1-ProceduralProgramming/0-main.ipynb
@@ -19,7 +19,8 @@
     "    * [TP 2](./4b-TP.ipynb)\n",
     "* [Dynamic allocation](./5-DynamicAllocation.ipynb)\n",
     "* [Input/output](./6-Streams.ipynb)\n",
-    "    * [TP 3](./6b-TP.ipynb)"
+    "    * [TP 3](./6b-TP.ipynb)\n",
+    "* [Static and constexpr](./7-StaticAndConstexpr.ipynb)"
    ]
   },
   {
diff --git a/1-ProceduralProgramming/7-StaticAndConstexpr.ipynb b/1-ProceduralProgramming/7-StaticAndConstexpr.ipynb
new file mode 100644
index 0000000..24bd3c7
--- /dev/null
+++ b/1-ProceduralProgramming/7-StaticAndConstexpr.ipynb
@@ -0,0 +1,304 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# [Getting started in C++](/) - [Procedural programming](./0-main.ipynb) - [Static and constexpr](./7-StaticAndConstexpr.ipynb)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "toc": true
+   },
+   "source": [
+    "<h1>Table of contents<span class=\"tocSkip\"></span></h1>\n",
+    "<div class=\"toc\"><ul class=\"toc-item\"><li><span><a href=\"#Static-keyword\" data-toc-modified-id=\"Static-keyword-1\">Static keyword</a></span></li><li><span><a href=\"#Constexpr\" data-toc-modified-id=\"Constexpr-2\">Constexpr</a></span></li></ul></div>"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Static keyword"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`static` may be seen as _at compile time_, whereas `dynamic` may be seen as _at runtime_.\n",
+    "\n",
+    "A reply to this [StackOverflow question](https://stackoverflow.com/questions/572547/what-does-static-mean-in-c) gives a rather good summary of what `static` means in C (we shall see [later](./2-ObjectProgramming/5-static.ipynb) a C++-only keyword that unfortunately share the same moniker):\n",
+    "\n",
+    "* Static defined local variables do not lose their value between function calls. In other words they are global variables, but scoped to the local function they are defined in.\n",
+    "* Static global variables are not visible outside of the C file they are defined in.\n",
+    "* Static functions are not visible outside of the C file they are defined in.\n",
+    "\n",
+    "Only the first one is really relevant in C++, as for quantities that should be accessible only in the current file C++ provides a concept of his own: the [**unnamed namespace**](../6-InRealEnvironment/5-Namespace.ipynb#Unnamed-namespace).\n",
+    "\n",
+    "Let's see the remaining case in action:\n",
+    "\n",
+    "\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "#include <iostream>\n",
+    "\n",
+    "void FunctionWithStatic()\n",
+    "{\n",
+    "    static int n = 0; // This initialisation occurs only at first call\n",
+    "                      // But `n` is not destroyed when the end bracket is reached and remains available\n",
+    "                      // in subsequent calls. However, `n` is available only inside this function.\n",
+    "    std::cout << \"The function has been called \" << ++n << \" times.\" << std::endl;    \n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "{\n",
+    "    for (int i = 0; i < 5; ++i)\n",
+    "        FunctionWithStatic();    \n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "It might be used for instance if you need to initialize something on the very first call of a function:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "// Pseudo-code\n",
+    "\n",
+    "void FunctionWithStatic()\n",
+    "{\n",
+    "    static bool is_first_call = true;\n",
+    "    \n",
+    "    if (is_first_call)\n",
+    "    {\n",
+    "        // Init stuff here on first call only, for instance something that requires heavy computation.\n",
+    "        // ...        \n",
+    "        is_first_call = false;\n",
+    "    }\n",
+    "    \n",
+    "    // ... code executed at each call\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Constexpr\n",
+    "\n",
+    "Let's consider the STL container `std::array`, which is the container of choice to store an array which size is known *at compile time* (containers will be seen more in depth in a [future notebook](./notebooks/5-UsefulConceptsAndSTL/3-Containers.ipynb))."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "#include <array>\n",
+    "\n",
+    "std::array<double, 3ul> my_array;"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Now imagine we want to init such an array with a size that results from a computation; let's say a Fibonacci series:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "// Recursive function - Xeus cling may not appreciate if you call this cell several times.\n",
+    "\n",
+    "auto fibonacci (std::size_t n) \n",
+    "{\n",
+    "    if (n == 0)\n",
+    "        return 0;\n",
+    "    if (n == 1)\n",
+    "        return 1;\n",
+    "    \n",
+    "    return fibonacci(n-1) + fibonacci(n-2);\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "#include <iostream>\n",
+    "std::cout << fibonacci(5) << std::endl;\n",
+    "std::cout << fibonacci(10) << std::endl;"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "#include <array>\n",
+    "std::array<double, fibonacci(4)> my_fibonacci_4_array; // COMPILATION ERROR!"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "This doesn't seem outlandish: a computation is involved and this computation happens at runtime - even if in fact all the required elements to perform it were available at runtime (there were for instance no argument read from command line involved).\n",
+    "\n",
+    "In C++ 03, you had two choices to resolve this\n",
+    "\n",
+    "- Using a macro...\n",
+    "- Or using [metaprogramming](./4-Templates/4-Metaprogramming.ipynb) which is a tad overkill... (and involves boilerplate code).\n",
+    "\n",
+    "C++ introduced the keyword `constexpr`, which indicates something happens at compile time. It might be used for just a variable, or for more complicated construct such as functions or classes. The only requirement is that all the subparts used are themselves `constexpr`."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "constexpr auto fibonacci_const (std::size_t n) \n",
+    "{\n",
+    "    if (n == 0)\n",
+    "        return 0;\n",
+    "    if (n == 1)\n",
+    "        return 1;\n",
+    "    \n",
+    "    return fibonacci_const(n-1) + fibonacci_const(n-2);\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "#include <array>\n",
+    "constexpr auto  fibonacci_index = 4ul;\n",
+    "std::array<double, fibonacci_const(fibonacci_index)> my_fibonacci_4_array; "
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`constexpr` function may also be used as runtime function, but in this case their results can't of course be used at compile time."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "#include <iostream>\n",
+    "\n",
+    "int i = 7;\n",
+    "++i; // i is by no stretch a compile time variable!\n",
+    "\n",
+    "std::cout << fibonacci_const(7) << std::endl; // ok!"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "`constexpr` becomes increasingly powerful over time:\n",
+    "\n",
+    "- The function `fibonacci_const` above does not in fact work before C++ 14: this version of the standard introduced the possibility to provide several `return` in a `constexpr` function.\n",
+    "- `constexpr` is added wherever possible in the STL. This is still a work in progress: if you look for instance the [CppReference page](https://en.cppreference.com/w/cpp/algorithm/count) for `std::count` algorithm, you will see this algorithm becomes `constexpr` in C++ 20."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "\n",
+    "© _CNRS 2016_ - _Inria 2018-2021_   \n",
+    "_This notebook is an adaptation of a lecture prepared by David Chamont (CNRS) under the terms of the licence [Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)](http://creativecommons.org/licenses/by-nc-sa/4.0/)_  \n",
+    "_The present version has been written by Sébastien Gilles and Vincent Rouvreau (Inria)_\n",
+    "\n"
+   ]
+  }
+ ],
+ "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"
+  },
+  "latex_envs": {
+   "LaTeX_envs_menu_present": true,
+   "autoclose": false,
+   "autocomplete": true,
+   "bibliofile": "biblio.bib",
+   "cite_by": "apalike",
+   "current_citInitial": 1,
+   "eqLabelWithNumbers": true,
+   "eqNumInitial": 1,
+   "hotkeys": {
+    "equation": "Ctrl-E",
+    "itemize": "Ctrl-I"
+   },
+   "labels_anchors": false,
+   "latex_user_defs": false,
+   "report_style_numbering": false,
+   "user_envs_cfg": false
+  },
+  "toc": {
+   "base_numbering": 1,
+   "nav_menu": {},
+   "number_sections": false,
+   "sideBar": true,
+   "skip_h1_title": true,
+   "title_cell": "Table of contents",
+   "title_sidebar": "Contents",
+   "toc_cell": true,
+   "toc_position": {},
+   "toc_section_display": true,
+   "toc_window_display": true
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/2-ObjectProgramming/5-static.ipynb b/2-ObjectProgramming/5-static.ipynb
index 8393533..ae6b2ed 100644
--- a/2-ObjectProgramming/5-static.ipynb
+++ b/2-ObjectProgramming/5-static.ipynb
@@ -23,76 +23,9 @@
    "source": [
     "## Static in C\n",
     "\n",
-    "We haven't dealt yet with the keyword `static`, which exists in C and could have been adressed in the procedural part of this lecture.\n",
+    "As a reminder, we have seen in a [previous notebook](./1-ProceduralProgramming/7-StaticAndConstexpr.ipynb#Static-keyword) the `static` keyword inherited from C. \n",
     "\n",
-    "As the C++ concept of **static method** uses up the same keyword and is not entirely related (even if both may be intertwined as we shall see in the [last section](./5-static.ipynb#Static-order-initialization-fiasco---and-its-fix)), we shall first review the C concept before studying the C++ one.\n",
-    "\n",
-    "First of all, `static` may be seen as _at compile time_, whereas `dynamic` may be seen as _at runtime_.\n",
-    "\n",
-    "A reply to this [StackOverflow question](https://stackoverflow.com/questions/572547/what-does-static-mean-in-c) gives a rather good summary of what `static` means in C:\n",
-    "\n",
-    "* Static defined local variables do not lose their value between function calls. In other words they are global variables, but scoped to the local function they are defined in.\n",
-    "* Static global variables are not visible outside of the C file they are defined in.\n",
-    "* Static functions are not visible outside of the C file they are defined in.\n",
-    "\n",
-    "Only the first one is really relevant in C++, as for quantities that should be accessible only in the current file C++ provides a concept of his own: the [**unnamed namespace**](../6-InRealEnvironment/5-Namespace.ipynb#Unnamed-namespace).\n",
-    "\n",
-    "Let's see the remaining case in action:\n",
-    "\n",
-    "\n"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "#include <iostream>\n",
-    "\n",
-    "void FunctionWithStatic()\n",
-    "{\n",
-    "    static int n = 0; // This initialisation occurs only at first call\n",
-    "                      // But `n` is not destroyed when the end bracket is reached and remains available\n",
-    "                      // in subsequent calls. However, `n` is available only inside this function.\n",
-    "    std::cout << \"The function has been called \" << ++n << \" times.\" << std::endl;    \n",
-    "}"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "{\n",
-    "    for (int i = 0; i < 3; ++i)\n",
-    "        FunctionWithStatic();    \n",
-    "}"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "It might be used for instance if you need to initialize something on the very first call of a function:\n",
-    "\n",
-    "````\n",
-    "void FunctionWithStatic()\n",
-    "{\n",
-    "    static bool is_first_call = true;\n",
-    "    \n",
-    "    if (is_first_call)\n",
-    "    {\n",
-    "        // Init stuff here on first call only\n",
-    "        ...        \n",
-    "        is_first_call = false;\n",
-    "    }\n",
-    "    \n",
-    "    ... // code executed at each call\n",
-    "}\n",
-    "\n",
-    "````"
+    "What follows is the same  keyword used in a very different context (even if the one we already know will pop up in an idion presented here).\n"
    ]
   },
   {
-- 
GitLab


From 51aaa9f7a358cc34d9bb969752eb945230d54306 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Gilles?= <sebastien.gilles@inria.fr>
Date: Mon, 3 May 2021 10:05:55 +0200
Subject: [PATCH 2/2] Rewrite slightly the constexpr section, and add the
 metaprogramming Fibonacci implementation in the adequate notebook.

---
 .../7-StaticAndConstexpr.ipynb                |  24 ++--
 4-Templates/4-Metaprogramming.ipynb           | 136 ++++++++++++++++++
 2 files changed, 147 insertions(+), 13 deletions(-)

diff --git a/1-ProceduralProgramming/7-StaticAndConstexpr.ipynb b/1-ProceduralProgramming/7-StaticAndConstexpr.ipynb
index 24bd3c7..a38706a 100644
--- a/1-ProceduralProgramming/7-StaticAndConstexpr.ipynb
+++ b/1-ProceduralProgramming/7-StaticAndConstexpr.ipynb
@@ -108,7 +108,7 @@
    "source": [
     "## Constexpr\n",
     "\n",
-    "Let's consider the STL container `std::array`, which is the container of choice to store an array which size is known *at compile time* (containers will be seen more in depth in a [future notebook](./notebooks/5-UsefulConceptsAndSTL/3-Containers.ipynb))."
+    "We've seen the allocation of an array on the stack follows this syntax:"
    ]
   },
   {
@@ -117,15 +117,15 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "#include <array>\n",
-    "\n",
-    "std::array<double, 3ul> my_array;"
+    "int array[5ul];"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
+    "where the size of the array is available at compile time (if not you have to use an array allocated on the heap at runtime).\n",
+    "\n",
     "Now imagine we want to init such an array with a size that results from a computation; let's say a Fibonacci series:"
    ]
   },
@@ -165,8 +165,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "#include <array>\n",
-    "std::array<double, fibonacci(4)> my_fibonacci_4_array; // COMPILATION ERROR!"
+    "double array[fibonacci(5)]; // COMPILATION ERROR!"
    ]
   },
   {
@@ -178,7 +177,7 @@
     "In C++ 03, you had two choices to resolve this\n",
     "\n",
     "- Using a macro...\n",
-    "- Or using [metaprogramming](./4-Templates/4-Metaprogramming.ipynb) which is a tad overkill... (and involves boilerplate code).\n",
+    "- Or using [metaprogramming](../4-Templates/4-Metaprogramming.ipynb) which is a tad overkill... (and involves boilerplate code).\n",
     "\n",
     "C++ introduced the keyword `constexpr`, which indicates something happens at compile time. It might be used for just a variable, or for more complicated construct such as functions or classes. The only requirement is that all the subparts used are themselves `constexpr`."
    ]
@@ -206,9 +205,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "#include <array>\n",
-    "constexpr auto  fibonacci_index = 4ul;\n",
-    "std::array<double, fibonacci_const(fibonacci_index)> my_fibonacci_4_array; "
+    "double array[fibonacci_const(5)]; // Ok!"
    ]
   },
   {
@@ -228,8 +225,7 @@
     "\n",
     "int i = 7;\n",
     "++i; // i is by no stretch a compile time variable!\n",
-    "\n",
-    "std::cout << fibonacci_const(7) << std::endl; // ok!"
+    "std::cout << fibonacci_const(7) << std::endl;"
    ]
   },
   {
@@ -239,7 +235,9 @@
     "`constexpr` becomes increasingly powerful over time:\n",
     "\n",
     "- The function `fibonacci_const` above does not in fact work before C++ 14: this version of the standard introduced the possibility to provide several `return` in a `constexpr` function.\n",
-    "- `constexpr` is added wherever possible in the STL. This is still a work in progress: if you look for instance the [CppReference page](https://en.cppreference.com/w/cpp/algorithm/count) for `std::count` algorithm, you will see this algorithm becomes `constexpr` in C++ 20."
+    "- `constexpr` is added wherever possible in the STL. This is still a work in progress: if you look for instance the [CppReference page](https://en.cppreference.com/w/cpp/algorithm/count) for `std::count` algorithm, you will see this algorithm becomes `constexpr` in C++ 20.\n",
+    "\n",
+    "We will see another use of `constexpr` in a [later notebook](../4-Templates/2-Specialization.ipynb#If-constexpr)."
    ]
   },
   {
diff --git a/4-Templates/4-Metaprogramming.ipynb b/4-Templates/4-Metaprogramming.ipynb
index 5c426ac..6add317 100644
--- a/4-Templates/4-Metaprogramming.ipynb
+++ b/4-Templates/4-Metaprogramming.ipynb
@@ -209,6 +209,142 @@
     "}"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Bonus: metaprogramming Fibonacci\n",
+    "\n",
+    "In [notebook about constexpr](../1-ProceduralProgramming/7-StaticAndConstexpr.ipynb), I said implementing Fibonacci series before C++ 11 involved metaprogramming; here is an implementation (much more wordy than the `constexpr` one):\n",
+    "\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "template<std::size_t N>\n",
+    "struct Fibonacci\n",
+    "{\n",
+    " \n",
+    "    static std::size_t Do()\n",
+    "    {\n",
+    "        return Fibonacci<N-1>::Do() + Fibonacci<N-2>::Do();\n",
+    "    }\n",
+    "    \n",
+    "    \n",
+    "};"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "// Don't forget the specialization for 0 and 1!\n",
+    "\n",
+    "template<>\n",
+    "struct Fibonacci<0ul>\n",
+    "{\n",
+    " \n",
+    "    static std::size_t Do()\n",
+    "    {\n",
+    "        return 0ul;\n",
+    "    }\n",
+    "    \n",
+    "    \n",
+    "};\n",
+    "\n",
+    "\n",
+    "template<>\n",
+    "struct Fibonacci<1ul>\n",
+    "{\n",
+    " \n",
+    "    static std::size_t Do()\n",
+    "    {\n",
+    "        return 1ul;\n",
+    "    }\n",
+    "    \n",
+    "    \n",
+    "};"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "#include <iostream>\n",
+    "\n",
+    "std::cout << Fibonacci<5ul>::Do() << std::endl;\n",
+    "std::cout << Fibonacci<10ul>::Do() << std::endl;"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "And if the syntax doesn't suit you... you could always add an extra level of indirection to remove the `::Do()` part:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "template<std::size_t N>\n",
+    "std::size_t FibonacciWrapper()\n",
+    "{\n",
+    "    return Fibonacci<N>::Do();\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "#include <iostream>\n",
+    "\n",
+    "std::cout << FibonacciWrapper<5ul>() << std::endl;\n",
+    "std::cout << FibonacciWrapper<10ul>() << std::endl;\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "As you can see, in some cases `constexpr` really alleviates some tedious boilerplate... \n",
+    "\n",
+    "It should be noticed that although these computations really occur at compile time, they aren't nonetheless recognized automatically as `constexpr`: "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "constexpr auto fibo_5 = FibonacciWrapper<5ul>(); // COMPILATION ERROR!"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "To fix that, you need to declare `constexpr`:\n",
+    "- Each of the `Do` static method (`static constexpr std::size_t Do()`)\n",
+    "- The `FibonacciWrapper` function (`template<std::size_t N> constexpr std::size_t FibonacciWrapper()`)\n",
+    "\n",
+    "So in this specific case you should really go with the much less wordy and more expressive expression with `constexpr` given in [aforementioned notebook](../1-ProceduralProgramming/7-StaticAndConstexpr.ipynb)"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
-- 
GitLab