WEBVTT

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

00:00.960 --> 00:06.000
In this video, we are going to look at the bind() function. To see why this is useful,

00:06.240 --> 00:12.450
let's start off by imagining we have some function which will compare its argument to a fixed value.

00:13.530 --> 00:18.570
This function match() will return true if it is passed a string whose value is "cat".

00:19.290 --> 00:23.460
And then, we could use this function as the predicate in an algorithm call.

00:24.270 --> 00:29.760
We could have some container, some algorithm which takes iterators into this container, and then we

00:29.760 --> 00:31.170
have match as the predicate.

00:32.550 --> 00:37.370
So here is some code which does that. We have our match() function.

00:37.740 --> 00:41.670
I am going to print out the argument, so we can see what is happening.

00:43.710 --> 00:45.840
We have a vector of strings.

00:46.560 --> 00:48.660
We have the count_if() algorithm.

00:49.200 --> 00:51.900
This will iterate over all the elements in the vector.

00:52.320 --> 00:58.230
It will call the match() function for each element and it will pass the element as the argument to match.

00:58.980 --> 01:03.180
And it will return the number of elements for which the function returned

01:03.180 --> 01:03.600
true.

01:06.630 --> 01:07.380
So there we are.

01:07.390 --> 01:10.680
We can see that the algorithm has called match(), with

01:10.680 --> 01:16.230
each element as argument. And there are two elements for which the function would return true.

01:16.860 --> 01:19.020
So this is all things that you've seen before.

01:19.980 --> 01:22.260
Suppose we want to make this more general.

01:22.980 --> 01:25.770
We do not want to have to compare to "cat" all the time.

01:26.340 --> 01:32.760
The obvious thing to do is to add a second argument to the call to match, but unfortunately that is

01:32.760 --> 01:35.460
not compatible with the syntax for algorithms.

01:37.170 --> 01:42.150
There is no way to tell the algorithm directly that we want "cat" to be the second argument of the call to

01:42.150 --> 01:42.510
match.

01:42.960 --> 01:48.510
If we tried to do this, for example, then we get a compiler error. "Function"

01:48.510 --> 01:50.220
does not take one arguments" (sic).

01:51.240 --> 01:53.250
So this is where bind() comes in useful.

01:54.210 --> 01:56.070
C++11 introduced bind().

01:56.100 --> 01:57.450
It is in the <functional> header.

01:58.140 --> 02:04.350
This takes a callable object as the first argument, and it will perform a partial function call.

02:04.830 --> 02:10.680
It will bind the remaining arguments to this function and return a new callable object.

02:12.890 --> 02:19.490
So if we call bind() with match() and "cat" as the arguments, this will bind "cat" to the match() function

02:20.000 --> 02:22.730
and return a new object with the bound argument.

02:23.450 --> 02:29.360
So if we call this returned object, it will call match() and pass "cat" as the argument.

02:29.780 --> 02:33.860
So that corresponds to the case where we had match() with one argument, in the first example.

02:36.920 --> 02:39.830
What we want is for match_cats() to take arguments.

02:39.830 --> 02:42.740
So we can pass elements as well, and you can do that.

02:43.340 --> 02:48.230
So if we pass an argument to match_cat(), it will be forwarded to match().

02:49.010 --> 02:54.230
So for example, if we have arguments one and two, then match() will be called with these two arguments

02:54.230 --> 02:54.860
and "cat".

02:55.730 --> 02:57.710
Or alternatively, you can mingle them.

02:57.710 --> 03:01.760
So you could have match with "arg1", followed by "cat", followed by "arg2".

03:04.360 --> 03:08.530
To do this, we need some way of saying where the arguments are going to appear, in the call to match(),

03:09.040 --> 03:11.140
and we have "placeholders" to do that.

03:11.920 --> 03:20.850
So when we want "arg1", we put underscore one. For the argument which we want to have filled in by

03:20.860 --> 03:22.780
"arg2", we put underscore two, and so on.

03:24.650 --> 03:28.430
These placeholders have their own namespace, and we have to use that, to get them.

03:29.660 --> 03:34.250
So, for example, we could call bind() with argument match placeholder one and "cat".

03:34.880 --> 03:40.970
So this will now capture "cat" as the second argument to bind(), and this will return an object which

03:40.970 --> 03:43.670
will call match() with the second argument as "cat".

03:44.030 --> 03:47.780
And the first argument has to be provided by the caller of match_cat().

03:48.650 --> 03:53.930
So, if we call match_cat() with argument "dog", for example, this will call match().

03:54.680 --> 03:58.010
The first argument will be the argument from match_cat(), which is "dog".

03:58.850 --> 04:01.640
And the second argument will be the bound argument, "cat".

04:02.390 --> 04:04.280
So this will call match() with the arguments

04:04.280 --> 04:05.390
"dog" and "cat".

04:08.330 --> 04:09.400
So let's try that out.

04:09.440 --> 04:11.750
The first part of the program is the same.

04:12.770 --> 04:17.000
We have the same match() function. In our main() function, call bind().

04:17.420 --> 04:23.420
We pass match() as the first argument, then the placeholder, then "cat". This will return an object

04:23.420 --> 04:26.180
which binds "cat" as the second argument to match().

04:26.600 --> 04:29.990
And will take one arguments, which will be the first argument to match().

04:31.290 --> 04:33.450
We call match_cat() with argument "dog".

04:33.930 --> 04:37.380
So this will call match(), with the argument "dog" in placeholder one,

04:37.740 --> 04:41.520
and "cat". "Dog" does not equal "cat".

04:41.550 --> 04:46.110
So we expect to see not matched. And that is what we get.

04:47.190 --> 04:49.980
And we can also use this for our algorithm call.

04:50.940 --> 04:52.110
So we have the same 

04:52.110 --> 04:55.200
match_cat() again. We have our vector of strings.

04:55.770 --> 04:57.270
Then we have the count_if() call.

04:57.810 --> 04:59.520
And then we pass match_cat().

05:00.330 --> 05:01.050
So this count_if()

05:01.050 --> 05:06.210
will iterate through all the elements of the vector. It will call match_cat with the element as

05:06.210 --> 05:07.050
the first argument.

05:07.650 --> 05:11.160
And that will call match(), with the element as the first argument.

05:11.580 --> 05:14.100
And "cat" as the second argument.

05:17.300 --> 05:18.410
So let's see what we get.

05:19.070 --> 05:21.020
So the first argument is the element.

05:21.260 --> 05:22.940
And the second argument is "cat".

05:23.660 --> 05:28.830
So we have two occurrences of the word "cat". Incidentally,

05:28.850 --> 05:30.710
you can put the arguments in a different order.

05:30.740 --> 05:36.050
So if you have two arguments to match_cat(), you can put the second argument in a placeholder.

05:36.410 --> 05:40.560
And then the first argument. So that result in the second argument being passed,

05:40.580 --> 05:41.290
then "cat",

05:41.300 --> 05:42.620
then the first argument.

05:45.580 --> 05:51.310
If you can remember the video about partial evaluation and C++14 lambdas,

05:51.640 --> 05:53.050
this may seem a bit familiar.

05:53.440 --> 05:57.430
In fact, you could also implement this using a lambda with a local variable.

05:58.180 --> 06:04.090
So we could have match_cat() as a lambda, with a local variable which is bound to "cat".

06:04.690 --> 06:11.680
It takes the animal as argument, and then it calls match(), with "animal" and the bound variable as arguments.

06:13.620 --> 06:16.830
So this time we defined match_cat() as this lambda expression.

06:19.050 --> 06:22.440
So this has a lambda-local variable, species, which is equal to "cat".

06:22.980 --> 06:28.830
It takes the animal as an argument, and then it calls match() with "animal" as the first argument and "species"

06:28.830 --> 06:29.520
as the second.

06:33.100 --> 06:34.690
And that gives exactly the same results.

06:36.550 --> 06:38.270
So we now have two ways of doing this.

06:38.290 --> 06:40.530
bind() and C++14

06:40.530 --> 06:45.010
lambdas. Personally, I think the lambdas are better, because it is clearer to see, from looking at

06:45.010 --> 06:46.030
the code, what it does.

06:48.010 --> 06:54.250
And one last thing you may occasionally come across. In C++98, there are much more basic versions

06:54.250 --> 06:54.790
of bind().

06:55.240 --> 07:01.990
They are called bind1st() and bind2nd(). bind1st() would only bind the first argument, and nothing else.

07:02.710 --> 07:05.860
bind2nd would bind the second argument, and nothing else.

07:06.400 --> 07:09.310
So these are very inflexible, and not very convenient.

07:09.820 --> 07:15.880
So that's why bind() was introduced in C++11. And then, in C++14, they realized they could use lambdas

07:15.880 --> 07:16.300
instead.

07:17.050 --> 07:22.150
So bind1st() and bind2nd() have been deprecated, and are now no longer part of C++.

07:22.750 --> 07:25.090
bind() is still there, if you want to use it.

07:25.480 --> 07:28.330
And we also have lambdas, which I think are the better alternative.

07:29.080 --> 07:30.460
Okay, so that is it for this video.

07:30.910 --> 07:31.750
I will see you next time.

07:31.750 --> 07:33.550
But until then, keep coding!
