Commit afbf8fac authored by GILLES Sebastien's avatar GILLES Sebastien
Browse files

Rewrite slightly the constexpr section, and add the metaprogramming Fibonacci...

Rewrite slightly the constexpr section, and add the metaprogramming Fibonacci implementation in the adequate notebook.
parent fadeee32
......@@ -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)."
]
},
{
......
......@@ -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": {},
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment