Hello again! In this video, we're going to look at if statements and switch in C++ 17.
Let's start off with something that we already know about. In C and early versions of C++ if you want
to write a for loop,
you have to declare the loop counter before the loop.
So this means that this variable i, which we are going to use to iterate over - some of array, presumably - is
actually defined in the enclosing scope.
So after the loop has finished, this variable i will still be in existence.
We can't create another variable called i.
And if you want another loop, you either have to use a different variable
Or we have to re-use this variable i, which in itself can create bugs.
If someone else has decided to use that variable and then we change the value to something that they were not
expecting.
In C++ 98, you now allowed to declare the variable inside the for loop, so this is a for loop initializer.
i is now a local variable inside the loop and once the loop is complete, then the variable i no longer
exists.
And if you want to write another loop, you can just do the same thing, "for (int i ..."
And you will get your own version of i.
So this is really a better way of doing things, because the loop counter is really an internal detail
of the loop. Code outside the deep should not need to know what type the loop counter is, what its name
is, what its value is.
If you do need to know the final value of the loop counter, you can always define a variable outside the
loop and copy into it.
So this makes your code clearer, more concise and safer. Which is all good stuff!
We often have situations where we want to check the return value from a function before we do something.
So this normally means we have to define a variable to hold the returned value and then write an statement.
But really, this is just a single operation.
If the return value is so and so, do this.
In this example, we are calling begin() to get the first element of a vector, and we are using this variable
"iter" to store the result, and then we want to make sure that the vector is not empty.
If the vector is empty, then the results of calling begin() is the same as the results of calling end().
So we want to check the vector is not empty before we process it. In C++17,
you can do this all in a single statement.
You can initialize the iterator.
So we have this initialization statement here and then semicolon and then we have our condition.
So this defines iter as a local variable to the if statement, and then it does the check.
And if this test is true, then it will execute the body of the if statement.
And this has similar advantages to the loop initializer. It does not get mixed up with the rest of
the code.
When we say that iter is local to the if statement, that also includes an "else" block, which corresponds to
the if.
So in this case, it's not really very useful because the else statement will only happen if the iterator
is invalid, which means you cannot do anything useful with it.
But in other situations, with a normal variable, that might be useful.
So here is that code in Visual Studio. We have our vector.
Then the old way. We get the iterator to the first element, then we compare it to the result of
calling end().
And if that is different, then it is safe to use the iterator.
Then we have the C++17 version, where we initialize the iterator inside the if statement.
So this will call begin(),
store the result and then compare it to the result of calling end. Unfortunately,
Visual C++ doesn't actually support this. "Requires C++ 17", but if you look in the project properties,
we are using C++ 17!
So there you are, four years after C++ 17, and it cannot - and it is still not fully supported.
People often ask me why I do not cover C++ 20 in my courses.
There is the reason. We still do not have complete support for C++ 17. And C++ 20 is obviously much less
complete.
So I am going to use MinGW instead, I use Notepad++ and MinGW for writing code for videos, on Windows.
I only use Visual Studio for demonstrations, because it is a bit easier.
So this is MinGW.
This is a port of GNU C++ for Windows.
The editor is Notepad++, which is a free program. Not the Notepad that comes with windows!
This is quite different. And infinitely better!
So I have got the same code here.
I am not sure if you can actually see that,
because it is a bit smaller, but it is actually the same. Honest!
So that's how you get C++ 17 with GCC and also clang.
And then the name of the file.
And right, so it does actually know how to compile C++ 17 code. And then we can execute it.
The output file is called "a.exe", unless you ask for it to be called something else.
So there we are, we get the same resultswith both forms of the code.
And you can also do this with a switch statement. So instead of creating a variable to store the result
of the function call and then switching on that, you can do it all in a single statement.
So here's a simple program which uses a switch statements.
I mean, this is really C code, iterating over array with an integer.
So perhaps it's not the best example of Modern C++! But we do have this C++ 17 feature with the initializer
in the switch statement.
So we have this C-style string with some whitespace characters. We have some spaces and also
this tab character.
And the point of this program is to count the number of spaces in this string.
We have this variable here that we're going to use to count the number of whitespaces.
So every time we encounter a whitespace character, we're going to increment it.
And then we iterate over this array.
And then for each element, we gets the current character and we have a switch.
So let's remind ourselves how switch statements work. When the program runs, the
program will examine this character 'c', so this is some numeric value, and then it will jump to the case label that matches it.
So if C is a space character, it will jump to this case, if it is a tab, it will jump to here and if it is a newline, it will
jump to here.
And then once it has jumped to a case, it will execute all the code until it encounters a break statement.
So it can actually execute across case labels.
So this means if c is a space or a tab or a new line, it is going to execute the same code, which is to
increment the counter.
And then when it gets to the break, it will jump out of the switch statement and go on to the next iteration
through the loop.
If it is anything other than a space, tab or newline, it is going to jump to the default label. Which will
just jump out of the switch again and go to the next element.
So again, Visual C++ will not compile this code, so we have to get back to...
So there we are. The text is, "How much white space in here?"
And the answer is five, so one, two, three.
Four.
Five.
Yes, there is an extra space after the tab. That confused me!
So we say in this case that the code will fall through the case labels until it finds a break statement.
There were other languages which work differently. In some languages,
only one case statement is ever executed.
So if you have an empty case that would presumably be an error. But in C++, it just keeps falling through
until it finds a break statement.
And this can be quite useful as in this program.
On the other hand, if you make a mistake and forget to put in a break statement, then it can be rather
bad.
So in this example, we have people who work in different locations in the company, and we want to
assign them a car, depending on where they work.
So we have this employee location, which is presumably some sort of enumerated type, and we do a switch
on it.
So if they work in head office, they get a nice swanky car. If they work in sales they get a fairly average
car.
And if they work in the warehouse, they get to drive a truck.
So that's the theory anyway.
But the programmer forgot to put a break statement in.
So when this runs, if the employee location is head office, then it's going to set the vehicle type
to Mercedes. Then it's going to fall through to sales. Then it wil set the vehicle type to Peugeot. Then it will fall
through and set the vehicle type to truck.
So in fact, every employee will end up driving a truck, which is probably not going to make you very
popular!
Some compilers will actually give you a warning here, which is quite helpful because it tells you that
you may need to check program logic. On the other hand, if you did actually intend to fall through,
then it is annoying.
It is just more noise in your compiler output.
And if you have a setting which treats all warnings as errors. Or if you have a coding standard
which says you are not allowed to have any warnings at all, then it is very annoying!
What usually happens in that case is people just get annoyed and hack their code to shut the compiler up,
which is not really what we want to happen.
C++ has things called attributes.
These are nothing like Java attributes!
You can't go and implement a database query system with them. An attribute is just simply an instruction
to the compiler, and it cannot change the meaning of the code.
To write an attribute, we put it inside a pair of square brackets, and the language defines quite
a few of these.
I'll be going through all of them.
But as we are talking about switches and C++ 17, this seems like a good point to cover it.
So to use the fallthrough attribute, we put it in an empty statement. So that just means we put a semicolon
after it, like that. And that will tell the compiler that we mean to fall through and it is not a mistake
and please do not give a warning.
So here is the code in visual C++ again. Which again, does not compile.
So we are.
The code compiles without any warnings.
So if we - Let's say we try to make it warn on everything.
OK, we get a warning for using an unused variable, but we do not get the [warning] for falling
through, which is what we are trying to avoid.
OK, so that's it for this video.
I'll see you next time, but meanwhile, keep coding!