WEBVTT

00:00.150 --> 00:07.320
Hello again! In this video, we are going to look at maps in C++17. C++17 has some new features which

00:07.320 --> 00:09.360
make working with maps a little easier.

00:10.860 --> 00:13.200
The first one is called a structured binding.

00:13.800 --> 00:16.800
This is an easy way for accessing data structures.

00:17.460 --> 00:23.790
We can write a single statement, which will declare some local variables and bind them to members of

00:23.790 --> 00:29.910
a compound data structure, and the types of these variables will be deduced for us by the compiler.

00:31.860 --> 00:35.310
This is implemented as a, kind of, more general version of auto.

00:36.450 --> 00:39.570
So in C++11, we can write statements like this.

00:40.200 --> 00:43.680
"i" will be a variable of type int, with initial value

00:43.680 --> 00:46.660
42. In

00:46.680 --> 00:47.260
C++17,

00:47.280 --> 00:51.840
You can put multiple variables in here, and you can have a compound object in here.

00:52.380 --> 00:57.480
Obviously, the number of variables here must be equal to the number of members of this object.

01:01.080 --> 01:04.560
So we can do something like this, we can have a pair object on the right hand side.

01:05.010 --> 01:11.370
This has two members, so we can use this to create and initialize two local variables.

01:12.240 --> 01:14.160
So this will define a local variable

01:14.160 --> 01:22.440
"i", of type inst with the initial value 1, and a variable "d", of type double, with initial value

01:22.440 --> 01:22.800
3.142.

01:25.530 --> 01:26.880
So let's try that out.

01:27.240 --> 01:33.810
So we have our pair, here. And then we have our structured binding, which will initialize these variables

01:33.810 --> 01:34.680
from the pair.

01:35.310 --> 01:37.800
And then we just print out the values of the variables.

01:43.970 --> 01:44.570
And there we are.

01:45.080 --> 01:47.600
"i" is 1, and "d" is 3.142.

01:50.730 --> 01:52.470
So how are these useful with maps?

01:52.770 --> 01:57.270
Well, one thing we can do is to make loops more readable. In C++11,

01:57.630 --> 01:58.320
we can do this.

01:58.320 --> 02:03.720
We can write a range-for loop, but this variable here will be an element of the map.

02:04.230 --> 02:05.370
So that is going to be a pair.

02:06.030 --> 02:09.450
So to get the data, we have to use the first member for the key,

02:09.840 --> 02:15.600
and the second member for the value. In C++17, we can write a structured binding.

02:16.020 --> 02:18.300
We can create local variables for this loop.

02:18.900 --> 02:25.860
The first variable, "name", will be the key, and the second variable, "score", will be the value.

02:26.490 --> 02:31.050
And then, in the loop body, we can use these meaningful names instead of "first" and "second".

02:33.520 --> 02:35.890
So let's try this. We have our favourite map.

02:36.730 --> 02:40.430
We are going to print it out, using the range-for loop that we have used so far.

02:41.410 --> 02:44.380
And then we're going to write another loop, with a structured binding.

02:52.010 --> 02:52.610
So there we are.

02:52.940 --> 02:58.550
So we get a list of all the elements, with the key and the value. And with the structured binding,

02:58.550 --> 02:59.900
we get the same list as well.

03:04.890 --> 03:08.730
We can also use a structured binding to check the return value from insert().

03:09.120 --> 03:12.330
So you will remember, this returns a pair, with an iterator and a bool.

03:13.200 --> 03:19.260
We can use a structured binding to create local variables. So this represents the iterator from the returned

03:19.260 --> 03:21.300
value, and that is the bool.

03:23.390 --> 03:29.230
And then we can write code, which looks a bit more normal. If we dereference this iterator, then we get

03:29.240 --> 03:30.050
another pair.

03:30.380 --> 03:35.000
This is going to be the pair which is the element of the map. And then we can use another structured

03:35.000 --> 03:36.410
binding to get the data out of that.

03:36.950 --> 03:42.080
So the first variable, "name", is going to be the key. And the second variable, "score" is going to be the value.

03:44.690 --> 03:45.980
So let's try this.

03:46.280 --> 03:53.240
So we have our call to insert(). Then we use a structured binding to split out the iterator and the bool

03:53.240 --> 03:54.500
from the returned pair.

03:55.910 --> 04:00.590
Then we can check the bool. And if we want the data from the element, then we can just dereference

04:00.590 --> 04:03.620
the iterator and use another structured binding to get the data.

04:12.160 --> 04:18.280
So we tried to insert an element with the key "Graham". There already is one, so that failed. So we went

04:18.280 --> 04:19.750
into the "else" branch of the loop.

04:22.190 --> 04:27.200
And then we can get the details of the element which is already there, by dereferencing the iterator.

04:30.910 --> 04:36.100
In the last video, we talked about the subscript operator, which gives "insert or assign" functionality,

04:36.670 --> 04:38.290
but it has some limitations.

04:39.160 --> 04:44.170
The insert() member function does not have these limitations, but it can only insert new elements.

04:45.220 --> 04:49.690
So C++17 has a new member function, which provides the best of both worlds.

04:50.500 --> 04:55.980
This will insert a new element, if there is no element with the key that we want.

04:56.620 --> 05:01.660
If there already is an element with that key, then it will overwrite the value, so it is going to assign

05:01.720 --> 05:02.410
to the element.

05:03.160 --> 05:06.970
And this takes two arguments, which are the key and the value of the element.

05:08.410 --> 05:11.920
This will return a pair, like insert(), so we can find out what happened.

05:12.730 --> 05:15.130
The first member is an iterator to the element.

05:16.000 --> 05:19.720
If it is a new element, it will be an iterator to the new element.

05:20.530 --> 05:25.570
If it assigned to an existing element, then that will be an iterator to the old element.

05:26.890 --> 05:32.830
The bool will be true if it inserted a new element, and it will be false if it performed an assignment.

05:33.310 --> 05:35.710
So in the case where it does insert a new element,

05:36.010 --> 05:38.740
the return value is exactly the same as for insert().

05:42.480 --> 05:44.790
So here we go again with our favourite map.

05:45.350 --> 05:47.430
(Perhaps - I am getting a bit tired of this one, actually!)

05:49.500 --> 05:53.070
So we called insert_or_assign(), instead of insert()

05:53.460 --> 05:56.490
We are going to pass a key which is already in the map.

05:56.880 --> 06:01.080
So we expect this to assign, and not create a new element.

06:01.800 --> 06:03.210
So we should go into this branch.

06:10.230 --> 06:16.490
Okay, so we had an existing element with the name "Graham". This had the score 78, and we have now assigned

06:16.500 --> 06:20.940
it to have the score 66, so we've assigned to the value of that element.

06:23.760 --> 06:29.000
And this has all the advantages of the insert() member function. We can use values which do not have

06:29.020 --> 06:34.260
a default constructor. If any exceptions are thrown, then the operation has no effect.

06:36.490 --> 06:40.000
And finally, let's go really crazy about C++17 features!

06:40.480 --> 06:44.140
So you might remember that we can have an initializer inside an if statement.

06:44.680 --> 06:50.110
So, for example, we can call a function, get its return value and then follow these different branches,

06:50.110 --> 06:51.610
depending on the returned value.

06:52.630 --> 06:56.170
When you have a structured binding, that counts as an initializer.

06:56.740 --> 07:01.570
So you are allowed to do things like this. So you can call insert_or_assign(),

07:02.850 --> 07:08.610
use a structured binding to get the bool, and then use that bool as the conditional for the if statement.

07:09.150 --> 07:14.310
So depending on whether you inserted or modified an element, you can follow different branches.

07:17.200 --> 07:18.360
So let's look at that.

07:20.450 --> 07:22.850
So here is our call to insert_or_assign().

07:23.240 --> 07:30.080
We have now moved that inside the if statement. We are initializing this bool from the return value, and

07:30.080 --> 07:31.250
then we can branch on it.

07:39.930 --> 07:40.500
And there we are.

07:40.710 --> 07:44.100
So we get the same result as before, but with one less line of code.

07:45.270 --> 07:46.680
Okay, so that us it for this video.

07:47.010 --> 07:47.820
I will see you next time.

07:47.820 --> 07:49.890
But until then, keep coding!
