(lively music)
Frank: Okay, welcome back.
In this video, we'll finish off
what we started in the previous video.
So let's get a little bit more complicated now
and look at a couple more examples.
I'm going to reduce this a little bit here.
All right, so here's test four
and I've got two pieces to test four.
Let me expand them both and I'll
I'll walk through them.
The first one, I have written a function
and that function is called filter_vector.
It's right here.
It returns nothing and what does it expect?
It expects a std vector of integers and its const
so I cannot modify it from in here.
It's called vec and a std function.
That's a function object.
And what does that function object expect?
An integer.
What does it return? A boolean.
That's what the syntax says.
I know the syntax may look a little wonky but
it just a matter of getting used to it.
It's not complicated.
And what is the name of that parameter? Func.
This is a function object.
So I can call that function object
simply by saying func and passing an integer into it.
Any kind of integer,
whether it's a literal or a variable name.
And this guy will return a boolean that I can use.
So that's what's really happening here.
I'm displaying the left bracket
and then I've got a range base FOR loop here
that's looping over this vector.
And for each integer I in the vector,
I'm calling func and passing it in.
What does this func do? I have no idea.
That's the real power here.
I could care less what is happening in that function.
All I know is that
I'm a filter vector function and I get a function.
I'm calling that function.
I really don't know what it does.
I don't care what it does.
The only thing that's important is that
it expects an int and returns a bool.
So in this case if it returns true,
I'm gonna display that value
and then I'm just closing this with a bracket.
Okay, so it will make sense now
when you see when I call it
so let me scroll up just a little bit.
I'm right here on test four.
So I'm saying test four, that's right here.
Here's my vector of numbers called NUMs
and I'm gonna call filter_vector
and I'm gonna pass in NUMs, that's this guy.
And now I'm gonna pass in the function
that I want called every time in here.
Well I'm gonna pass in the lambda expression.
Stateless, it expects an int and it returns a boolean.
That's exactly what we set up here.
So what is this guy gonna do?
It's gonna return true when X is greater than 50
and this guy here will be true
only whenever each one of those I's is greater than 50.
So what does this do?
This only prints out values that are greater than 50
right there.
60, 70, 80, 90, a 100.
In this example, I'm just using a different lambda.
I'm only gonna display values that are less than
or equal to 30
and you can see them display right here.
And in this case, I'm only displaying values
that are greater than or equal to 30
and less than or equal to 60
so we're displaying 30, 40, 50, 60.
This is pretty cool.
I think you can really wrap your head around this
and see how powerful these lambdas are.
Also what's very important to understand is
the programmer that wrote this function
doesn't really care what this function does.
Right here for example, only greater than 50
less than equal to 30,
it's up to perhaps another programmer
that's using this filter_vector function
to decide, you know, what's the logic here.
Okay, now this guy right here
is called the predicate lambda
and I mentioned that in the slides in the previous lecture.
This is a predicate lambda because it expects
one or more parameters and returns a boolean.
That's the definition of a predicate lambda
or a predicate function if you will.
So again, walk through this example and try 'em out
and you know change these lambdas to do different things
and you can see just how powerful this really is.
There are so many algorithms
in this general template library
that use these predicate lambda just like this.
So from a programmer's perspective,
we're working in here, right?
But the person or the team that wrote those algorithms
are expecting this kind of thing
and they could care less how we wanna sort something
or how we wanna compare something,
that's for our logic determine.
Try one more.
Oh, and by the way, I should mention
this line 95 right here,
we use this in C++ 14 or higher.
In C++ 20, we can replace this
with just this, auto func
and let the compiler figure out that it returns a boolean
and expects an initial parameter.
So that's pretty cool too.
But that's would, that would be a C++ 20.
Lemme scroll this up as well.
Okay, so now we're in test five
and it's these two pieces right here.
All right, so what's going on in test five?
Well, test five is a little bit different as well.
And you'll see this make more sense
when we talk about stateful lambdas
in the next couple of sections.
But in this case, look what I've got.
I've got a function called make lambda
and what does it return? Auto.
Let the compiler figure it out.
It's returning a lambda.
You can see right here, right?
It's return, there's my capture list, no parameters
and there's the body of the lambda, a sea of statement.
Wow, you know you wrap your head around this thing
and you're going, well what's going on here?
Well I'm calling a function that's returning a lambda.
It's not executing that lambda.
It's just returning the lambda.
Later on I can execute that lambda if I want.
And that's what I'm doing right here.
You can see right here I'm displaying test five right there.
Then I'm calling make_lambda,
that's my function
and I'm assigning whatever it's returning,
which is a lambda in this case,
to this lambda right here called L5
and now I'm calling it.
And when I call it, it instantiates the lambda,
executes that lambda that's being returned
and you could see what displays.
This lambda was made using make_lambda.
We could pass parameters.
We could do all kinds of things and again,
it makes more sense to see this in the stateful context.
So I'll leave those examples for the next couple of videos.
But you can see it's pretty cool, right?
That a lambda, that sorry that a function
can return a lambda
and those lambdas that we return
can be pretty complicated as well.
Let's move over to test six
and there's just a couple left, couple of examples.
And this one's a pretty easy example to understand
and we're over here in test six.
So what do we do here?
Well this is using auto in the lambda parameter list.
I mentioned this in the slides in the previous lecture.
Notice now I'm saying auto and auto.
So I'm telling the compiler, hey compiler
you figure out what's going on.
This is pretty cool because we're not to having to create
some generic template function here.
We're just doing it this way.
So again, L6 is the variable.
Let the compiler figure out the type
and what are we assigning to this variable? A lambda.
No capture, two parameters.
What are their types?
I don't know.
Let the compiler figure it out.
And within the body of that lambda,
all we're doing is we're displaying X
and we're displaying Y.
What's the type of X and Y? Again I don't know.
The compiler will figure it out.
So now that I've got my lambda,
my lambda expression in the variable L6, I can call it.
Right here, I'm calling it with two integers.
So the compiler sees this and says
oh, that's an int.
That's an int. Aha, int int.
10 20 is being displayed.
Now I'm displaying it.
I'm calling it with a double and an integer.
So it's displaying 100.3 and 200, right?
The double and the integer.
Here's two doubles.
That works too.
But this is where it's really neat.
I'm calling L6 now
and I'm passing in two person objects:
Larry 18, Curly 22.
These guys, the compiler's gonna say
oh those are person objects.
Remember I created that person class
up at the top of this file.
So it's gonna pass those things into this lambda,
execute the lambda
and it's gonna display person Larry 18, person Curly 22.
Same thing we passed in here.
Now that's pretty cool.
Now a couple of things that are happening here.
It's very important that whatever you pass into this
must overload this operator, right?
I mean we're displaying these guys
using this operator right here.
I've already, I have overloaded the insertion operator
in that person class that I've already created up there.
So this is really important.
Otherwise you're gonna get a compiler error
that may not be too easy to read
and it's gonna say something about operator
less than less than not defined somehow.
It's not a problem here
because the floats and the ints and the doubles
all support the overloaded insertion operator.
Last example, this example right here is test seven.
Also really straightforward example.
What we're doing here
and lemme scroll this up just a little
so we can see it a little bit better.
I'm right here in test seven.
What I've done is I've created a vector
of person objects called stooges.
So there are Larry, Mo and Curly.
Larry's 18, Mo is 30, Curly's 25.
Now what I'm doing
is I'm calling some of the standard template library
algorithm functions. Okay, I'm gonna use two of them.
I'm gonna use std sort and std for each.
They take in lambda expressions or function objects.
In this case I'm using lambdas.
So I'm calling std sort
and basically it says, well what do you want to sort?
Where does it start? Where does it end?
So begin stooges, end stooges, right?
There's my vector.
I wanna start at the beginning, go to the end.
Remember this is just an alternate syntax for stooges
.begin and .end.
We can do it like begin like this or like this.
Either way it works.
And here is the lambda expression.
Remember std sort is expecting a function object.
So that's why I'm gonna send it.
No capture list,
two parameters by const reference.
The first one is one person,
the other is the other person.
It's sorting.
So when you're sorting, you're comparing two things
and moving them around.
Well how does this guy know where to move things around?
Well you need to tell it which one is bigger.
So in this case, I'm returning P1 get the name
and if it's less than P2's name,
I'm gonna return true or false depending on this condition.
Based on that condition,
the std sort algorithm knows which one is greater,
which one is less than and it can do what its thing.
Now this is pretty powerful.
This is again a predicate lambda right here.
You can see that this is a predicate lambda right here.
We're passing in some parameters
and it's returning a boolean.
So that's exactly what's happening here
and that's exactly what std sort expects.
So what's going on?
I'm sorting the stooges vector by name.
Now when I finish this,
this std vector right here will be sorted.
Now I just want to display each element in there.
And to do that, I'm gonna use
another standard template library algorithm called for_each.
Now what does this do?
Well, where do you wanna start?
Where do you wanna end and what do you want to do?
So it's gonna loop through that vector.
That's what it's doing for each element in the vector.
it's gonna loop through that vector
and for each one of those elements,
it's going to call this lambda function right here.
It's gonna take that element in here,
Larry, Mo, Curly,
pass it into here and I'm just gonna display it.
So when I call this, look what happened right here.
Curly, Larry, Mo.
Notice it's sorted alphabetically, C-L-M, right?
Curly, Larry, Mo.
It used to be Larry, Mo, Curly.
So this function right here that we called
absolutely sorted that vector
based on the condition in our predicate lambda.
all right, so one more example and we're right here now.
I'm calling std sort again.
This time I'm sorting based on age.
I wanna sort based on age.
Same idea, right?
Gimme the two parameters
and return P1's age less than P2's age.
Now std sort knows
you know which one to put ahead of the other.
And once we do that,
we're gonna do this std for each again.
And this code and this code are exactly the same.
But look what happens over here.
Now we're gonna display Larry, Curly and Mo
but now they're sorted by age.
There you go.
This gives you a, I think a pretty good introduction
to different kinds of stateless lambdas
using references, by value, objects and so forth.
In the next video, we'll switch over
and we'll start talking about stateful lambda expressions.
So I'll see you in that one.