Hello again! In this video, we are going to look at maps in C++17. C++17 has some new features which
make working with maps a little easier.
The first one is called a structured binding.
This is an easy way for accessing data structures.
We can write a single statement, which will declare some local variables and bind them to members of
a compound data structure, and the types of these variables will be deduced for us by the compiler.
This is implemented as a, kind of, more general version of auto.
So in C++11, we can write statements like this.
"i" will be a variable of type int, with initial value
42. In
C++17,
You can put multiple variables in here, and you can have a compound object in here.
Obviously, the number of variables here must be equal to the number of members of this object.
So we can do something like this, we can have a pair object on the right hand side.
This has two members, so we can use this to create and initialize two local variables.
So this will define a local variable
"i", of type inst with the initial value 1, and a variable "d", of type double, with initial value
3.142.
So let's try that out.
So we have our pair, here. And then we have our structured binding, which will initialize these variables
from the pair.
And then we just print out the values of the variables.
And there we are.
"i" is 1, and "d" is 3.142.
So how are these useful with maps?
Well, one thing we can do is to make loops more readable. In C++11,
we can do this.
We can write a range-for loop, but this variable here will be an element of the map.
So that is going to be a pair.
So to get the data, we have to use the first member for the key,
and the second member for the value. In C++17, we can write a structured binding.
We can create local variables for this loop.
The first variable, "name", will be the key, and the second variable, "score", will be the value.
And then, in the loop body, we can use these meaningful names instead of "first" and "second".
So let's try this. We have our favourite map.
We are going to print it out, using the range-for loop that we have used so far.
And then we're going to write another loop, with a structured binding.
So there we are.
So we get a list of all the elements, with the key and the value. And with the structured binding,
we get the same list as well.
We can also use a structured binding to check the return value from insert().
So you will remember, this returns a pair, with an iterator and a bool.
We can use a structured binding to create local variables. So this represents the iterator from the returned
value, and that is the bool.
And then we can write code, which looks a bit more normal. If we dereference this iterator, then we get
another pair.
This is going to be the pair which is the element of the map. And then we can use another structured
binding to get the data out of that.
So the first variable, "name", is going to be the key. And the second variable, "score" is going to be the value.
So let's try this.
So we have our call to insert(). Then we use a structured binding to split out the iterator and the bool
from the returned pair.
Then we can check the bool. And if we want the data from the element, then we can just dereference
the iterator and use another structured binding to get the data.
So we tried to insert an element with the key "Graham". There already is one, so that failed. So we went
into the "else" branch of the loop.
And then we can get the details of the element which is already there, by dereferencing the iterator.
In the last video, we talked about the subscript operator, which gives "insert or assign" functionality,
but it has some limitations.
The insert() member function does not have these limitations, but it can only insert new elements.
So C++17 has a new member function, which provides the best of both worlds.
This will insert a new element, if there is no element with the key that we want.
If there already is an element with that key, then it will overwrite the value, so it is going to assign
to the element.
And this takes two arguments, which are the key and the value of the element.
This will return a pair, like insert(), so we can find out what happened.
The first member is an iterator to the element.
If it is a new element, it will be an iterator to the new element.
If it assigned to an existing element, then that will be an iterator to the old element.
The bool will be true if it inserted a new element, and it will be false if it performed an assignment.
So in the case where it does insert a new element,
the return value is exactly the same as for insert().
So here we go again with our favourite map.
(Perhaps - I am getting a bit tired of this one, actually!)
So we called insert_or_assign(), instead of insert()
We are going to pass a key which is already in the map.
So we expect this to assign, and not create a new element.
So we should go into this branch.
Okay, so we had an existing element with the name "Graham". This had the score 78, and we have now assigned
it to have the score 66, so we've assigned to the value of that element.
And this has all the advantages of the insert() member function. We can use values which do not have
a default constructor. If any exceptions are thrown, then the operation has no effect.
And finally, let's go really crazy about C++17 features!
So you might remember that we can have an initializer inside an if statement.
So, for example, we can call a function, get its return value and then follow these different branches,
depending on the returned value.
When you have a structured binding, that counts as an initializer.
So you are allowed to do things like this. So you can call insert_or_assign(),
use a structured binding to get the bool, and then use that bool as the conditional for the if statement.
So depending on whether you inserted or modified an element, you can follow different branches.
So let's look at that.
So here is our call to insert_or_assign().
We have now moved that inside the if statement. We are initializing this bool from the return value, and
then we can branch on it.
And there we are.
So we get the same result as before, but with one less line of code.
Okay, so that us it for this video.
I will see you next time.
But until then, keep coding!