Hello again! In this video, we are going to look at the function call operator.
We already know about procedural programming and object-oriented programming in C++.
There are some other paradigms as well, and functional programming is one of those. In procedural programming,
we have a sequence of commands.
So typically, if you are processing a vector, you have a loop. And on each iteration through the
loop,
That will
process one element of the vector. With functional progtamming, you typically have a tree or a chain of function
calls, in which one function takes some data and returns that, and that becomes the input to the next
function.
For example, if you are processing a vector, you have a function to process an element and then a
function which will "apply" that.
So this will call the first function with each element as argument, and then you may have another
function which gets the return values and builds them up into a vector or prints them to screen
or something.
In C++, we use callable objects to implement functional programming.
There are probably some people who say that you cannot do functional programming properly in C++, but
that's a different argument.
In fact, we can create callable objects in C with function pointers.
So we have a function pointer to some function, and that behaves like a data variable. So we can copy this
function pointer, so we can pass it to functions and return it.
But we can also call it like a function.
So if we put some brackets after the name of this pointer and put some arguments in, then this will call the
original function with those arguments.
In C++, we have a more object oriented way, or a nicer way to do this.
We can have a class which has a function call operator.
So objects of this class will be callable objects. So they behave just like any other data variable.
But you can also call them like a function by invoking this function call operator. And a class which
does
this is known as a functor. (I have to be careful
how I say that!)
To make a functor, we define a function call operator, which is "operator ()". It looks rather
strange when you first see it.
So this is a free form operator.
It can take any arguments, any number, any type. And return any type. And it can do anything you
want it to, really.
To invoke this, we just put the name of the object, followed by a pair of brackets with the arguments in between.
And that will call the operator on that object, with the arguments.
So here is an example.
We have a class with a function call operator.
There it is.
It takes one argument, which is an int, and it returns bool.
And this will be true if the argument is exactly divisible by 2.
So n mod 2 will be 0 for an even number and 1 for an odd number.
And then we create an object of this class. We call the object with 6 as argument. And then this
will return true if 6 is even and false if it is not.
So let's see what happens. And we get, 6 is an even number.
So that has called this function with argument 6.
Let's look at an example now, which is a bit closer to functional programming.
So in main(), we have a vector. We have another object of this class.
So that is the same class as we had before, with the function call operator.
Then we print out the elements of this vector, just to show what we have.
And then we have this function.
So this function will actually apply the functor to the vector.
So this will call the [functor], with every element in the vector as its argument.
So we call this function in the main(). We pass the functor as an argument.
So let's see what that does.
So there is our vector. We expect that 4, 12 and 36 are even, and the rest are not.
And that is what we get.
So in this example, we just print out the even numbers.
We could do something else. For example, we could create a new vector, which contains only
the even numbers.
What sort of class should a functor be?
Well, really, it is just meant to be a wrapper around the function, so it should be very simple.
So do not go mad and put lots of member functions and data members in.
Sometimes it can be useful to add a data member to maintain state.
So when a function has seats, this means there is some variable which keeps its value between function
calls.
For example, if you have a function which generates a sequence number, so this is something which
increases by one, every time you call it, you would make the sequence number a static [variable] of the
function and then the next time the function gets called, the static variable will keep its value.
And then you can increment it.
So it always does that consistently. With a functor, you can do that by providing a data member.
So we are going to generalize our class now. Instead of finding out whether the argument is divisible
by 2,
we want to be able to find out if it is divisible by some arbitrary number. And this number is going to
be a member of the class.
And then this will be set in the class constructor.
So we have our vector again.
Then we have an object of this class. We pass 3 as the argument to the constructor.
So that means that this state member, the state of this will be 3.
So this will check whether the number is divisible by 3.
And then we have the same do_it() function again.
So this will call the function on every element in the vector.
And there we are. 12 is divisible by 3, and 36 is divisible by 3.
Okay, so that is it for this video.
I will see you next time.
But meanwhile, keep coding!