Hello again!
In this video, we are going to look at some examples of using constexpr if. Just to remind ourselves,
this is a compile-time
"if" statement. The conditional is a constant expression.
If the conditional evaluates to true, then the compiler will compile the code in this branch and
ignore the code in the else branch.
And then, if it is false, the compiler will ignore the code from the if branch, and only compile the code
which is in the else branch.
So the compiler will ignore all the paths which are not taken.
The old classic. The Fibonacci function. A recursive function.
So this is a normal function, not a template or a member function.
All this code is going to be evaluated at run-time.
We want to make sure that "n" is always positive, in here.
So we only make the recursive calls, if "n" is greater than 1.
If "n" is less than or equal to 1, then we return the value of "n", and that terminates the recursion.
We do not keep on going, with ever more negative values of "n".
If we want to implement this as a compile-time function, we could do it, using a template with a value
parameter.
So this number "N" will be some value of an int.
In the general case, we just call the instantiations for "N-1" and "N-2".
To terminate the recursion, we need to have some specializations.
So these go below the general case.
We have a specialization with the empty brackets. For "N" equals 1,
we return 1, and similar for N == 0.
And then we call it. We passe a suitable initial value of "N" as the parameter.
So the compiler will instantiate this with N equals 10.
This will call the instantiations for 9 and 8. Those will call the instantiations for N equals 8,
7 and 6, and so on.
And then, when we get down to "N" equals 1 and "N" equals 0, it will use these specializations, which
terminate the recursion.
So there we are.
So, we have to write all this code, just to implement an "if" statement.
Unless we are using C++17, in which case we can just write the "if" statement directly.
So if "N" is greater than 1, then the compiler will instantiate this with a body which returns
the results of the recursive calls. If "N" is less than or equal to 1, then the compiler will instantiate
this with a body which returns "N".
So, in effect, we have got the compiler to write these specializations for us.
We have already seen an example of where we had to write convoluted template code. just to implement an
"if" statement.
That was when we were dealing with variadic templates.
So these are function templates with variable numbers of arguments.
We have this cunning plan for processing them, where we have a template function with a single parameter,
and then a parameter pack.
So in effect, we pass all the arguments to this function. And then, each time, it pops off the front element
from the list. And then, calls itself recursively, to process the rest of the list.
To terminate this, we need to write a single-parameter function, and this time it has to go above
the generic version.
And then we have the same main() function we had before.
So we start off, by instantiating a function with three arguments.
So that processes the first argument, then equals an instantiation with two arguments.
That processes the second argument. And then it calls the non-variadic template to process the last
argument.
So again, we have to go to a lot of trouble,
just to write a compile-time "if" statement. In C++17, we can just write it directly.
So, if there is at least one argument remaining in this parameter pack, then we call ourselves
recursively, to process it.
If there are no arguments left, then that code disappears, and the function will just return normally.
So that is the end of the recursion.
So you can see we instantiate the function with three arguments, then with two and then with one.
So again, we have in effect got the compiler to write the single template argument for us.
Okay, so that is it for this video.
I will see you next time.
But until then, keep coding!