WEBVTT

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

00:01.140 --> 00:03.870
In this video, we are going to look at callable objects.

00:04.400 --> 00:09.120
A callable object is anything which supports the function call operator.

00:10.230 --> 00:12.480
C++ now has quite a few of these.

00:13.170 --> 00:19.890
There's the original pointer to function from C, which still works, with non-member functions. Pointers

00:19.890 --> 00:21.720
to member functions are quite different.

00:22.230 --> 00:28.920
We will be looking at those in the next video. Functors: classes which define the function called operator.

00:29.850 --> 00:35.700
Lambda expressions, which are functors written by the compiler. And the result of calling bind().

00:36.840 --> 00:38.790
So these are all callable objects.

00:39.120 --> 00:45.180
We can write the name of the object, followed by a pair of brackets which contain arguments, and this will

00:45.180 --> 00:46.650
result in a function being called.

00:47.730 --> 00:54.060
These callable objects all have different types. If we have a pointer to a function which takes string

00:54.060 --> 01:00.240
and returns int, this will be a different type from a lambda expression which takes string and returns

01:00.240 --> 01:00.540
int.

01:02.200 --> 01:07.270
Sometimes it's useful to be able to work with different callable objects which have the same signature,

01:07.630 --> 01:09.430
the same arguments and return type.

01:10.000 --> 01:11.560
And now there is a way of doing that.

01:13.850 --> 01:17.930
C++11 has a standard function class in the <functional> header.

01:18.740 --> 01:22.190
This has a private member which stores a callable object.

01:23.330 --> 01:29.120
It is a template class and the parameter of the template is the signature of the object.

01:30.590 --> 01:31.910
This looks a bit strange at first.

01:32.240 --> 01:37.430
We have the return type, then open bracket, then the arguments, then close bracket.

01:38.030 --> 01:43.970
So that is similar to the function prototype, but without the name of the function. And the member can

01:43.970 --> 01:47.000
store a callable object which has this signature.

01:48.890 --> 01:53.000
The function class is implemented using inheritance and virtual functions.

01:53.780 --> 01:55.840
It performs what's known as "type erasure".

01:56.450 --> 02:01.670
So if you have a function object, you cannot tell what type of callable object is in there.

02:02.120 --> 02:05.900
You don't know whether it is a lambda, or a functor, or anything else.

02:08.180 --> 02:09.770
So why would this be useful?

02:10.460 --> 02:14.390
One thing you can do is, you can have a function call, and you can say that one of the arguments to this

02:14.390 --> 02:16.460
function is a function object.

02:17.090 --> 02:22.190
And then in that argument you can pass any kind of callable object which has the right signature.

02:23.240 --> 02:29.000
You can also create a container of function objects, and you can populate that with any kind of

02:29.000 --> 02:31.010
callable object with the right signature.

02:33.380 --> 02:34.550
There are some limitations.

02:34.880 --> 02:40.790
The function prototype must match the template parameter, so there is no support for overloading.

02:41.690 --> 02:47.000
And also there is runtime overhead. Because it is implemented using inheritance and virtual functions,

02:47.510 --> 02:51.930
then invoking the callable object involves an indirection.

02:51.980 --> 02:54.620
So that is similar to virtual function overhead.

02:57.100 --> 03:02.710
Another limitation is that the function class assumes that all callable objects have the same size.

03:03.640 --> 03:08.860
If you have a functor, that may not be true. A function is a class. It can have data members, and those

03:08.860 --> 03:12.100
data members can make the object bigger than the space that is available.

03:12.730 --> 03:17.260
In that case, the function object will allocate memory on the heap, to make sure it has enough room.

03:17.620 --> 03:19.240
So there is no danger of an overflow.

03:19.570 --> 03:23.230
But that does add to the runtime and the memory usage.

03:26.860 --> 03:32.470
So because of these limitations, we should really only use the function class when we need a polymorphic

03:32.470 --> 03:33.340
function object.

03:34.510 --> 03:39.940
If you just want somewhere convenient for storing a callable object, use a variable and declare its

03:39.940 --> 03:40.900
type as auto.

03:41.620 --> 03:48.910
So for example, a function pointer, or a lambda expression. You just have a variable of type "auto".

03:49.360 --> 03:52.330
So this will retain the type of the callable object.

03:52.630 --> 03:57.610
The compiler will know what the type is. And you can call it directly, just like you would normally.

03:57.940 --> 04:00.190
There is no overhead from indirection.

04:03.100 --> 04:04.720
So, here is some code for trying this out.

04:05.140 --> 04:10.390
We are basically going to repeat the exercise from the last video, where we had a vector of strings, and

04:10.390 --> 04:14.920
we were counting the number of cats. In that one, we used the count_if() function from the <algorithm> header.

04:15.700 --> 04:20.890
This time, we are going to implement our own version of count_if(), using a function object as the argument.

04:24.260 --> 04:27.320
So here it is. We have our function, count_strings().

04:27.740 --> 04:29.240
This will take a vector of strings.

04:29.840 --> 04:31.220
And then we have a function object.

04:32.180 --> 04:37.980
This will iterate through the elements of the vector, and it will call the function for each element.

04:38.450 --> 04:41.270
And it will count the number of times that the function returns

04:41.270 --> 04:41.660
true.

04:42.740 --> 04:45.260
So that is basically the functionality of count_if().

04:48.270 --> 04:51.060
We have various functions we are going to pass to it.

04:51.060 --> 04:52.590
We have a non-member function.

04:53.550 --> 04:56.970
We have functor, which defines a function call operator.

04:58.410 --> 05:01.110
We have this function, which we are going to pass to bind().

05:01.650 --> 05:03.210
And then we also have a lambda expression,

05:04.720 --> 05:05.590
later one in the main().

05:05.830 --> 05:07.660
So here is our vector of strings again.

05:08.290 --> 05:11.140
Then we call count_strings(). First of all, with a function pointer.

05:11.740 --> 05:14.110
So that is a pointer to the non-member function.

05:15.490 --> 05:16.930
Then we call it with the functor.

05:16.940 --> 05:19.010
We need to pass an object of the functor.

05:19.030 --> 05:20.170
So we call the constructor.

05:21.580 --> 05:23.440
Then we have our lambda expression.

05:25.430 --> 05:26.750
And then we call bind().

05:27.680 --> 05:34.190
So this returns a callable object. And then we pass the callable object to our count_strings() function.

05:34.910 --> 05:37.040
So these should all return the same value.

05:38.540 --> 05:38.940
Okay.

05:38.960 --> 05:39.470
And there we are.

05:39.920 --> 05:41.390
So that is it for this video.

05:41.930 --> 05:42.830
I will see you next time.

05:42.830 --> 05:45.170
But until then, keep coding!
