WEBVTT

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

00:01.080 --> 00:04.050
In this video, we are going to look at constexpr functions.

00:06.060 --> 00:09.790
In C++11, we can say that a function is constexpr.

00:10.470 --> 00:16.290
This means that the arguments are constant expressions, and the return value is also a constant expression.

00:17.430 --> 00:21.420
These constexpr functions are executed at compile time.

00:21.930 --> 00:24.960
This uses an interpreter which runs inside the compiler.

00:25.290 --> 00:29.010
So this is something which understands most of the C++ language.

00:29.820 --> 00:35.220
So you can write this code in normal C++, and you get normal C++ error messages.

00:37.410 --> 00:41.650
To do this, we put the constexpr key word before the function declaration.

00:42.300 --> 00:52.030
So this function miles_to_km() is constexpr. A constexpr function must be what is known as "pure".

00:52.770 --> 00:59.430
So this means it does not modify the arguments. And also, it does not modify any global or static variables.

01:00.090 --> 01:04.200
So a pure function is not allowed to change anything outside the function body.

01:06.290 --> 01:12.110
constexpr functions are in line, by definition. Because the function call is omitted.

01:12.620 --> 01:18.890
And this also means we can have multiple definitions, so we can include a constexpr function definition

01:19.250 --> 01:24.440
in a header. And we can include that header in as many source files as we like. And we are not going

01:24.440 --> 01:25.010
to get any

01:25.010 --> 01:27.590
errors about violating the "one definition rule".

01:28.580 --> 01:33.890
So this means you can use constexpr functions in header-only libraries. And this is actually a very

01:33.890 --> 01:38.480
common practice now, with C++, to distribute libraries as headers only.

01:39.080 --> 01:44.390
So you can just include these into your program, and you do not need to worry about compiling source files

01:44.720 --> 01:46.400
and linking them into your binary.

01:49.400 --> 01:55.550
It is also possible to call a constexpr function with arguments which are not constant expressions. And

01:55.550 --> 01:58.860
that means that the return value will not be a constant expression.

01:59.900 --> 02:05.390
If you are using this in a situation where the return value is supposed to be a constant expression,

02:06.050 --> 02:07.340
then you get a compiler ever.

02:08.090 --> 02:11.780
But if it is not, then the function will be evaluated at runtime.

02:12.050 --> 02:14.840
So that will work just like any other function in C++.

02:15.830 --> 02:20.270
And the reason for allowing this, is so you can have a function which does the same thing for constant

02:20.270 --> 02:25.400
expressions and variables, without having to write two almost identical versions.

02:28.150 --> 02:31.630
So here is our constexpr function, miles_to_km().

02:32.410 --> 02:34.990
So we can call this with a constant expression as argument.

02:35.680 --> 02:38.140
The return value will be a constant expression.

02:39.400 --> 02:43.930
We can call it with an argument, which is a variable. So not a constant expression, because it

02:43.930 --> 02:48.880
can be modified. And the return value will not be a constant expression.

02:49.720 --> 02:52.180
And this is going to be evaluated at runtime.

02:54.290 --> 02:59.150
I have put a dummy main() function in here, just so we do not get any annoying errors about not having a

02:59.150 --> 02:59.810
main() function.

03:01.310 --> 03:03.080
So there we are. That compiles.

03:04.130 --> 03:10.700
However, if we have a... If we call this function with an argument which is not a constant expression,

03:11.630 --> 03:15.080
and the return value is supposed to be a constant expression.

03:15.470 --> 03:21.500
So we are using this to initialize a constexpr variable. Which has to be initialized from a constant expression

03:22.370 --> 03:24.080
Then this is going to give a compiler error.

03:27.890 --> 03:29.640
So let's look at that. "Expression

03:29.640 --> 03:31.640
"did not evaluate to a constant.

03:32.240 --> 03:37.610
"Failure was caused by non-constant argument... See usage of 'arg'".

03:38.120 --> 03:40.010
So that is an extremely clear error message.

03:40.250 --> 03:46.010
It tells you what the problem is, where it is, and why there is an error. So, ten out of ten to Microsoft

03:46.010 --> 03:50.630
for that! Just imagine what that would have been, if this was a template function!

03:53.980 --> 03:58.120
constexpr functions are useful for performing calculations at compile time.

03:58.780 --> 04:04.210
So this means the calculation is only done once. Or, at least, only once for every time you compile the

04:04.210 --> 04:10.660
program. As opposed to every time that the program is run, by every user, on every site where it is installed.

04:12.310 --> 04:13.810
There is no runtime overhead.

04:13.810 --> 04:19.030
It takes no time at all to do this calculation, because it has been done before the program starts. And this

04:19.030 --> 04:21.410
means your program will use less electricity.

04:22.780 --> 04:26.020
In C++11, the rules were very limiting.

04:26.320 --> 04:30.490
You could only have a single return statement in the body of a constexpr function.

04:30.910 --> 04:36.970
So that is similar to the C++11 rules for lambda expressions. In C++14,

04:37.330 --> 04:43.120
these were relaxed quite a bit. As they were for lambda expressions. And now you can have multiple statements

04:43.120 --> 04:45.340
in the body of a constexpr function.

04:46.120 --> 04:51.940
You can also declare local variables in the function body, provided they are initialized, and not static.

04:52.810 --> 04:54.370
And you can use flow control.

04:54.700 --> 04:59.800
You can have if statements, switch statements, and loops. Including rang-for loops.

05:02.880 --> 05:05.100
There are still restrictions on side-effects.

05:05.370 --> 05:11.820
The body of a constexpr function may not contain any code which could cause an action at run-time.

05:12.510 --> 05:14.160
Which includes memory management.

05:14.400 --> 05:20.460
So that means you cannot use things like string and vector; calling virtual functions, and throwing

05:20.460 --> 05:21.120
exceptions.

05:24.920 --> 05:27.140
You can also have member functions which are constexpr.

05:27.320 --> 05:31.850
So these take constant expressions as arguments, and return a constant expression.

05:32.900 --> 05:37.190
This is different from having a member function, which is const. A const member function

05:37.190 --> 05:39.980
means you cannot modify the object it was called on.

05:40.370 --> 05:40.880
So the

05:40.880 --> 05:43.120
"this" pointer is a pointer to const.

05:44.800 --> 05:46.000
In C++11.

05:46.000 --> 05:50.470
If you have a member function which is constexpr, then it was also const.

05:50.800 --> 05:54.250
So these functions could not modify the objects they were called on.

05:55.210 --> 05:58.290
In C++14, they are no longer const.

05:58.300 --> 05:59.950
So you can modify the object.

06:00.370 --> 06:06.460
If you want to prevent that, then you can declare them as const additionally. So you can have a member function which

06:06.460 --> 06:08.290
is constexpr and const.

06:11.210 --> 06:15.440
And finally, we can also have members of classes and structs which are constexpr.

06:15.950 --> 06:20.330
So these are initialized from a constant expression, and they cannot be modified.

06:21.620 --> 06:27.020
This is only possible if you declare the member as static. Which means it is not associated with any particular

06:27.020 --> 06:30.050
object. Which means it is available at compile-time.

06:31.070 --> 06:35.570
If you have a member which is not static, then it has to belong to a particular object.

06:36.230 --> 06:39.560
And you can only have objects at run-time, because you need to call the constructor.

06:41.050 --> 06:43.450
So that is why you have to declare them as static.

06:44.290 --> 06:45.760
Okay, so that is it for this video.

06:46.150 --> 06:47.020
I will see you next time.

06:47.020 --> 06:49.210
But until then, keep coding!
