WEBVTT

00:00.360 --> 00:04.530
Hello again! In this video, we are going to look at the function call operator.

00:05.640 --> 00:10.830
We already know about procedural programming and object-oriented programming in C++.

00:11.520 --> 00:18.000
There are some other paradigms as well, and functional programming is one of those. In procedural programming,

00:18.000 --> 00:19.680
we have a sequence of commands.

00:19.710 --> 00:25.650
So typically, if you are processing a vector, you have a loop. And on each iteration through the

00:25.650 --> 00:25.920
loop,

00:26.190 --> 00:26.700
That will

00:26.820 --> 00:33.720
process one element of the vector. With functional progtamming, you typically have a tree or a chain of function

00:33.720 --> 00:39.360
calls, in which one function takes some data and returns that, and that becomes the input to the next

00:39.360 --> 00:39.870
function.

00:41.160 --> 00:48.510
For example, if you are processing a vector, you have a function to process an element and then a

00:48.510 --> 00:49.890
function which will "apply" that.

00:50.250 --> 00:54.840
So this will call the first function with each element as argument, and then you may have another

00:54.840 --> 01:00.510
function which gets the return values and builds them up into a vector or prints them to screen

01:00.510 --> 01:01.020
or something.

01:01.680 --> 01:05.670
In C++, we use callable objects to implement functional programming.

01:06.210 --> 01:10.410
There are probably some people who say that you cannot do functional programming properly in C++, but

01:11.340 --> 01:12.510
that's a different argument.

01:15.640 --> 01:19.700
In fact, we can create callable objects in C with function pointers.

01:20.230 --> 01:27.130
So we have a function pointer to some function, and that behaves like a data variable. So we can copy this

01:27.130 --> 01:30.040
function pointer, so we can pass it to functions and return it.

01:30.790 --> 01:32.770
But we can also call it like a function.

01:33.760 --> 01:39.790
So if we put some brackets after the name of this pointer and put some arguments in, then this will call the

01:39.790 --> 01:42.340
original function with those arguments.

01:45.680 --> 01:50.090
In C++, we have a more object oriented way, or a nicer way to do this.

01:50.630 --> 01:53.450
We can have a class which has a function call operator.

01:54.080 --> 02:00.440
So objects of this class will be callable objects. So they behave just like any other data variable.

02:00.830 --> 02:06.710
But you can also call them like a function by invoking this function call operator. And a class which

02:06.710 --> 02:06.920
does

02:06.920 --> 02:10.250
this is known as a functor. (I have to be careful

02:10.250 --> 02:10.820
how I say that!)

02:15.220 --> 02:22.540
To make a functor, we define a function call operator, which is "operator ()". It looks rather

02:22.600 --> 02:23.980
strange when you first see it.

02:25.030 --> 02:26.940
So this is a free form operator.

02:26.950 --> 02:33.400
It can take any arguments, any number, any type. And return any type. And it can do anything you

02:33.400 --> 02:34.140
want it to, really.

02:36.170 --> 02:41.450
To invoke this, we just put the name of the object, followed by a pair of brackets with the arguments in between.

02:41.960 --> 02:45.470
And that will call the operator on that object, with the arguments.

02:46.190 --> 02:47.750
So here is an example.

02:48.170 --> 02:50.690
We have a class with a function call operator.

02:51.560 --> 02:52.240
There it is.

02:53.000 --> 02:57.620
It takes one argument, which is an int, and it returns bool.

02:58.340 --> 03:02.210
And this will be true if the argument is exactly divisible by 2.

03:02.840 --> 03:07.330
So n mod 2 will be 0 for an even number and 1 for an odd number.

03:09.020 --> 03:17.270
And then we create an object of this class. We call the object with 6 as argument. And then this

03:17.270 --> 03:21.740
will return true if 6 is even and false if it is not.

03:22.640 --> 03:26.720
So let's see what happens. And we get, 6 is an even number.

03:29.670 --> 03:31.770
So that has called  this function with argument 6.

03:34.660 --> 03:38.500
Let's look at an example now, which is a bit closer to functional programming.

03:39.100 --> 03:44.500
So in main(), we have a vector. We have another object of this class.

03:44.770 --> 03:48.550
So that is the same class as we had before, with the function call operator.

03:51.010 --> 03:55.030
Then we print out the elements of this vector, just to show what we have.

03:55.900 --> 03:57.270
And then we have this function.

03:57.280 --> 04:01.330
So this function will actually apply the functor to the vector.

04:01.810 --> 04:07.840
So this will call the [functor], with every element in the vector as its argument.

04:10.850 --> 04:15.680
So we call this function in the main(). We pass the functor as an argument.

04:18.860 --> 04:20.080
So let's see what that does.

04:22.930 --> 04:27.550
So there is our vector. We expect that 4, 12 and 36 are even, and the rest are not.

04:28.120 --> 04:29.260
And that is what we get.

04:30.910 --> 04:34.450
So in this example, we just print out the even numbers.

04:34.720 --> 04:39.100
We could do something else. For example, we could create a new vector, which contains only

04:39.100 --> 04:40.120
the even numbers.

04:42.450 --> 04:44.400
What sort of class should a functor be?

04:44.940 --> 04:49.500
Well, really, it is just meant to be a wrapper around the function, so it should be very simple.

04:49.860 --> 04:53.400
So do not go mad and put lots of member functions and data members in.

04:54.780 --> 04:59.490
Sometimes it can be useful to add a data member to maintain state.

04:59.970 --> 05:05.850
So when a function has seats, this means there is some variable which keeps its value between function

05:05.850 --> 05:06.270
calls.

05:06.960 --> 05:11.250
For example, if you have a function which generates a sequence number, so this is something which

05:11.250 --> 05:16.350
increases by one, every time you call it, you would make the sequence number a static [variable] of the

05:16.350 --> 05:22.170
function and then the next time the function gets called, the static variable will keep its value.

05:22.680 --> 05:23.880
And then you can increment it.

05:24.330 --> 05:30.570
So it always does that consistently. With a functor, you can do that by providing a data member.

05:31.950 --> 05:37.980
So we are going to generalize our class now. Instead of finding out whether the argument is divisible

05:37.980 --> 05:38.580
by 2,

05:38.940 --> 05:44.700
we want to be able to find out if it is divisible by some arbitrary number. And this number is going to

05:44.700 --> 05:46.020
be a member of the class.

05:47.710 --> 05:50.410
And then this will be set in the class constructor.

05:54.430 --> 05:56.020
So we have our vector again.

05:56.800 --> 06:01.990
Then we have an object of this class. We pass 3 as the argument to the constructor.

06:02.830 --> 06:07.510
So that means that this state member, the state of this will be 3.

06:07.510 --> 06:10.810
So this will check whether the number is divisible by 3.

06:12.880 --> 06:15.640
And then we have the same do_it() function again.

06:15.940 --> 06:20.230
So this will call the function on every element in the vector.

06:26.360 --> 06:30.500
And there we are. 12 is divisible by 3, and 36 is divisible by 3.

06:32.030 --> 06:33.650
Okay, so that is it for this video.

06:33.740 --> 06:34.630
I will see you next time.

06:34.640 --> 06:36.980
But meanwhile, keep coding!
