WEBVTT

00:00.150 --> 00:00.690
Hello again!

00:01.080 --> 00:07.920
In this video, we are going to look at some examples of using constexpr if. Just to remind ourselves,

00:07.920 --> 00:09.090
this is a compile-time

00:09.090 --> 00:12.240
"if" statement. The conditional is a constant expression.

00:13.230 --> 00:18.690
If the conditional evaluates to true, then the compiler will compile the code in this branch and

00:18.690 --> 00:20.700
ignore the code in the else branch.

00:21.480 --> 00:27.720
And then, if it is false, the compiler will ignore the code from the if branch, and only compile the code

00:27.720 --> 00:29.040
which is in the else branch.

00:29.490 --> 00:32.580
So the compiler will ignore all the paths which are not taken.

00:35.780 --> 00:40.100
The old classic. The Fibonacci function. A recursive function.

00:40.880 --> 00:44.690
So this is a normal function, not a template or a member function.

00:45.500 --> 00:48.090
All this code is going to be evaluated at run-time.

00:48.860 --> 00:51.920
We want to make sure that "n" is always positive, in here.

00:52.550 --> 00:56.210
So we only make the recursive calls, if "n" is greater than 1.

00:56.810 --> 01:03.140
If "n" is less than or equal to 1, then we return the value of "n", and that terminates the recursion.

01:03.470 --> 01:07.460
We do not keep on going, with ever more negative values of "n".

01:10.680 --> 01:16.260
If we want to implement this as a compile-time function, we could do it, using a template with a value

01:16.260 --> 01:16.800
parameter.

01:17.760 --> 01:20.370
So this number "N" will be some value of an int.

01:21.450 --> 01:26.010
In the general case, we just call the instantiations for "N-1" and "N-2".

01:27.210 --> 01:30.840
To terminate the recursion, we need to have some specializations.

01:31.410 --> 01:33.020
So these go below the general case.

01:33.480 --> 01:38.190
We have a specialization with the empty brackets. For "N" equals 1,

01:38.190 --> 01:41.730
we return 1, and similar for N == 0.

01:43.560 --> 01:47.580
And then we call it. We passe a suitable initial value of "N" as the parameter.

01:48.300 --> 01:51.000
So the compiler will instantiate this with N equals 10.

01:51.510 --> 01:57.540
This will call the instantiations for 9 and 8. Those will call the instantiations for N equals 8,

01:57.540 --> 01:58.800
7 and 6, and so on.

01:59.490 --> 02:05.370
And then, when we get down to "N" equals 1 and "N" equals 0, it will use these specializations, which

02:05.370 --> 02:06.690
terminate the recursion.

02:08.770 --> 02:09.460
So there we are.

02:10.780 --> 02:14.170
So, we have to write all this code, just to implement an "if" statement.

02:15.400 --> 02:20.140
Unless we are using C++17, in which case we can just write the "if" statement directly.

02:20.890 --> 02:26.680
So if "N" is greater than 1, then the compiler will instantiate this with a body which returns

02:27.130 --> 02:33.460
the results of the recursive calls. If "N" is less than or equal to 1, then the compiler will instantiate

02:33.460 --> 02:35.170
this with a body which returns "N".

02:36.700 --> 02:40.720
So, in effect, we have got the compiler to write these specializations for us.

02:44.400 --> 02:49.970
We have already seen an example of where we had to write convoluted template code. just to implement an

02:49.980 --> 02:50.790
"if" statement.

02:51.240 --> 02:53.820
That was when we were dealing with variadic templates.

02:54.300 --> 02:57.360
So these are function templates with variable numbers of arguments.

02:58.440 --> 03:04.560
We have this cunning plan for processing them, where we have a template function with a single parameter,

03:04.560 --> 03:06.000
and then a parameter pack.

03:06.930 --> 03:12.990
So in effect, we pass all the arguments to this function. And then, each time, it pops off the front element

03:12.990 --> 03:17.760
from the list. And then, calls itself recursively, to process the rest of the list.

03:18.780 --> 03:24.540
To terminate this, we need to write a single-parameter function, and this time it has to go above

03:24.540 --> 03:25.770
the generic version.

03:29.120 --> 03:31.250
And then we have the same main() function we had before.

03:32.000 --> 03:35.750
So we start off, by instantiating a function with three arguments.

03:36.170 --> 03:40.700
So that processes the first argument, then equals an instantiation with two arguments.

03:41.120 --> 03:46.920
That processes the second argument. And then it calls the non-variadic template to process the last

03:46.940 --> 03:47.450
argument.

03:50.430 --> 03:52.260
So again, we have to go to a lot of trouble,

03:52.500 --> 03:59.250
just to write a compile-time "if" statement. In C++17, we can just write it directly.

04:00.150 --> 04:05.610
So, if there is at least one argument remaining in this parameter pack, then we call ourselves

04:05.610 --> 04:07.410
recursively, to process it.

04:08.490 --> 04:13.410
If there are no arguments left, then that code disappears, and the function will just return normally.

04:13.710 --> 04:15.450
So that is the end of the recursion.

04:20.070 --> 04:24.690
So you can see we instantiate the function with three arguments, then with two and then with one.

04:25.140 --> 04:29.610
So again, we have in effect got the compiler to write the single template argument for us.

04:30.750 --> 04:32.250
Okay, so that is it for this video.

04:32.790 --> 04:33.660
I will see you next time.

04:33.660 --> 04:36.030
But until then, keep coding!
