(pleasant electronic music)
-: Okay, welcome back,
so let's continue with the examples of stateful lambdas.
In this case, I'm in Test Seven.
And you can see that I've scrolled that up right up here,
so you can see my Test Seven right here.
This basically is equivalent to the last,
Test Six that we just did.
The difference is that rather than capture by value
and one by reference,
I'm capturing by reference and two by value.
So it's just mixing things up, so let's go through this.
Here I'm saying capture everything by reference.
Except X and Z, capture them by value.
So again, you can see it's exactly the same thing.
Just, you know, done a little bit different, syntactically.
We're gonna capture everything by reference except X and Z,
so X and Z will be copied.
They're gonna be captured by value.
That's 100 and 300.
And everything else, which in this case is Y,
will be captured by reference.
So there's my reference.
And again, we're gonna increment everything by 100,
and display everything, just like we did before,
we should get the same output.
So I'm gonna call my lambda.
X will be incremented by 100,
that's my local X right here.
Y will be incremented by 100 through this reference,
so that's gonna be 300.
Z will be incremented by 100,
so that'll be 400 right here.
And we're gonna display X, Y, and Z
which are 200, 300, 400 and just what we see.
Now when I come back, from the function,
I'm gonna display X, Y, and Z again,
we're gonna display these guys.
So that would be 100 300 300, 100 300 300.
Okay, perfect.
So now let's do a few with some objects.
In Test Eight,
I've defined a person class that's really really similar
to the person class that I defined
in the previous date list lambda demo.
So you can see what's happening here.
I've got my class person.
I've overloaded the insertion operator to be a friend,
just to allow us to display person objects real easily.
A person has a name and an age.
I've got a default constructor.
And you can use this in text,
I didn't really talk about this much in the class,
but, it's just a handy way of telling the compiler
"Hey compiler, generate a default constructor for me."
Sometimes it's real handy,
'cause you can actually be very explicit
to tell whoever's reading your code,
whatever other programmer is reading your code,
that this is exactly what you intended.
So I've got an overloaded constructor here,
a copy constructor here,
and I've done the same thing, a destructor here.
And then I've got my get and my sets and so forth.
Now you can see I've added three methods here.
And let me just expand this, you can see what they're doing.
There we go.
So in this case, I have a method called change person one.
And another one called change person two
and another one called change person three.
They pretty much do exactly the same thing.
Notice that they return auto,
because we're returning a lambda.
And I just want to compiler to figure out the syntax for me.
So in this case, what are we capturing?
We're capturing this, which is the this pointer.
We're capturing by value,
we're capturing by reference,
if you remember from the slides,
these three things are equivalent.
They all capture by reference.
What I would like you to do is always use this version.
The version with the equal sign is deprecated in C++ 20.
That means it's not gonna be supported going forward.
That's a good thing, because when a programmer sees that,
they're thinking capture by value.
And that doesn't happen here,
what's happening is capture by reference.
So it can be confusing and it always has been confusing.
And this one, you know,
why do it when we really wanna capture the this pointer,
so, I would encourage you to use that version only.
So, look what this does.
I'm capturing this.
And the parameters being passed into this
are the new name and the new age,
and all I'm doing is I'm setting name and age
to new name and new age respectively.
Notice that right here,
I don't have to say this name.
Right, or this age, right here.
The compiler will figure that out for us
because of the syntax.
You know, what other name could we be talking about,
it has to be these guys.
So the compiler figures that out.
So what we're gonna do is, when we call these methods,
the lambda will capture the this pointer
and modify those values.
Not a big deal, pretty straightforward,
but I just wanted to show you how you could capture this.
And later on we're gonna do another example
where we capture it another way.
So, let's take a look at the test here.
And I'm only gonna go over this one,
you can see, all three of them,
there's three different examples here,
all three will give you the exact same output.
But in this case, look what we've got,
we've got person, Larry, 18,
so Larry is a person, he's 18 years old.
So now this is what we're going to do,
we're gonna capture using this,
which is that one in person one.
So notice what I'm doing is I'm calling change person one,
in person, a method call, just like before, right?
But this guy is returning a lambda.
That's pretty cool.
So now that I've got my lambda right here, I can call,
I can say change person one and pass in Moe in 30.
Moe is gonna be passed in for the name, and 30 for the age,
and they're gonna change.
So when I display,
you're going to see something else display, right?
You're gonna see, instead of Larry,
you're gonna see Moe display,
let me show you right here, alright, so,
remember this is our first output statement right here,
it just displays Larry, looks like that.
Now we're calling change person one
and then displaying that value.
And in this case, we're displaying Moe.
And you could see here,
where I'm capturing by value and by reference,
it's changing to Curly and to Frank,
because I'm passing in Curly and Frank.
So you can see, that's a good example
that shows how all three of these captures are equivalent.
But as I said, you know, stick to using the this capture,
that's what you're gonna see out there.
I don't think you would ever see this out there,
I've never seen it out there.
Even though it's perfectly legal to use.
And I've seen this a few times, but,
if you're capturing instance variables from an object,
use this, it's really, really clear what your intention is.
Okay, so, that would be our Test Eight.
And let's take a look at this one here.
This is similar, I've got a class called lambda.
And it's got a private instance, variable Y.
You can see my constructor right here.
And there's my operator, does that look familiar?
It should look familiar, right,
because that's exactly like the closure class
that gets created from a lambda expression, remember that?
We've got our function call operator,
we're passing in the X.
This is exactly like the example
that we went over in the slides.
So let's take a look at the equivalence
of a class like this,
versus a lambda expression, they're the same.
And sometimes you'll see these, instead of classes,
you'll see this as a struct.
And everything public, but that's okay,
it works exactly the same way.
Okay, so let's look at Test Nine,
let me scroll up a little bit.
Alright, so here's Test Nine,
I'm displaying the header there.
I've got Y, which is 100.
And I'm creating an instance of lambda one,
and I'm passing in Y, which is 100.
Alright, that is going to create this guy,
it's gonna call this constructor,
it's gonna initialize this to 100.
Just like we would expect.
Now when I call lambda one, I'm passing the 200 here.
And it's gonna add 100 and 200 and display 300.
That's what's happening when we're using this class.
In this case, I've got a lambda variable, lambda two.
Notice what we're doing, we're capturing Y by value.
It's got a parameter X,
and it's displaying the sum of X and Y.
Exactly the same thing, when I call lambda two with 200,
you get exactly the same output.
So you can see
that these two examples are equivalent.
Right, that and that, they're equivalent.
This kind of code is what's being generated
from that lambda expression.
And this is really important to understand,
because it really gives you a good insight
into how these lambdas work behind the scenes.
It's really nice to be able to use them,
but it's even better to be able to understand
how they work behind the scenes.
Alright, so let's do one more, and that would be Test 10.
And for Test 10, I've got a lot going on here,
so let me walk through this really slowly.
In this example, I created a class called people.
And that people class
has a bunch of person objects in it,
right, it's got a stood vector of persons.
So people consists of a bunch of person objects.
And then I've also got this instance variable right here
called max people.
Think of that as the maximum number of people
that you will be able to display.
So if there's 100 person objects in this vector,
and I try to display them,
I should only be allowed to display 10
or five or three or whatever this value is here.
And the constructor just sets this guy to 10 by default,
or gives it whatever value the user supplies.
I've got a copy constructor that I'm just defaulting,
and I think that's about it, I don't need a destructor
because there's no pointers or anything here.
Now I've got an add method,
and what that add method does
is it allows me to add a person to my vector right here.
And I can pass in the person's name and the person's age.
And I can use emplace back,
which creates a person object from these values,
and pushes it back onto the people vector.
If you don't recall emplace back,
you can go back and look at the vectors lecture,
in the STL section.
Now I've got another method right here
called set max people.
And the user passes in a number
and we're setting that instance variable
to whatever they pass in, and the getter as well.
Okay, so.
Now, let's see how we can use a lambda with this.
Okay, so now, I've got a method called get people
and get people returns, a vector of persons.
So basically what we're going to do is,
we're going to return all the person objects
in that people class, whose age is greater than max age.
And I'm only gonna return less than max people,
I'm not gonna go over that value.
That's really important.
Now the interesting thing here is,
when the user calls get people,
the user really has no idea about max people.
They're just sending in an age.
So I might have 100 people in this people vector,
that are over 50, I'm only gonna display 10 of them,
because of that value.
Let's see how this works.
First thing I'm doing is I'm creating
a local stood vector of persons called result,
it's empty right now.
And I've got account.
Now I'm gonna use
the standard template library algorithm copy if.
And I'm gonna copy matches to this result
as long as they match the criteria that I mentioned.
So right here, I'm gonna say stood copy if.
What are we copying from?
People bot begin,
where are we copying up to, people dot N,
so I'm using the entire people Vector.
And what I'm going to do is, when I've got a match,
I'm going to use stood back inserter.
Which basically pushes back
whatever I'm getting into that result,
that vector that I'm building right here.
And obviously what I'm getting is persons, right?
So now it comes to lambda,
when do we actually do this copy if, right?
There's an if in there,
so it has to match something.
And let me expand this out
so you can see all the code right here.
So look at what we're doing here.
First of all, we're capturing this.
That allows me access to that guy
which is an instance variable in this class.
As well as the vector I'm capturing count by reference,
that's this guy right here, because I need to modify that.
and I'm expecting a person reference that's constant.
And that's what copy if is gonna give me.
Right, now what's my predicate,
well my predicate basically says if P's age,
that's the object that's being passed into me,
is greater than this max age.
And I'm going to pre-increment count
and make sure that it's less than equal to max people.
That's it, that's pretty cool.
So you can see what we're using here,
we're using that lambda to gain access to the object.
And once we have access to the object,
we can use all kinds of good stuff.
So at this point, we need that,
we need that access to the object to get to max people.
Okay, so now, we're good.
At this point we're gonna return result,
and it's gonna contain as many people
that match that criteria as I'm allowed to print.
Now the idea here is, sure,
this function could have accepted
the max number of people to print.
But suppose there are two entities here, right,
one that is setting that policy,
and this one that's using this,
and this function really shouldn't know about the other.
Alright, so let's run through a test here,
see how all this works.
So here we are in test 10, and I've got people, friends,
and then I'm gonna add Larry, Curly, Moe, Frank, and James.
Now I'm going to call get people.
Now remember, when I called this guy, the max was 10.
So the most that I could display was 10,
that was the default parameter in my constructor.
When this function returns,
I'm gonna have a stood vector of person objects,
that's what this is,
that contains all the people whose age is 17 or over.
Now this is basically everybody,
you can see everybody here is 17 or older, right?
So once I get that, I'm just gonna loop through that result,
and display them all,
and you can see right here, I'm getting them all.
Now I'm gonna set the maximum number of people to three.
And I'm gonna call that function exactly the same way,
friends dot get people 17.
I'm still gonna get five matches, right?
But I'm only gonna get three back, because the max is three.
Now when I come over here and display this,
I'm gonna see Larry Curly and Moe only.
So now, let's take a look at this last example here.
Remember, we've still got three as the max.
Not that it matters in this case.
But in this case, I wanna get people over 50.
Well the only person over 50 is James.
So all we get back is James.
Had there been 40 people that are over 50,
I only would've gotten three of them back
and displayed only three.
This can be really handy,
sometimes you've got a game going on and you've got players,
you've got a whole bunch of players,
but only a certain number of players
meet a certain criteria.
And there may be so many of them
that you just wanna randomly pick one two or three
or give you the first three back, or the first 10 back,
depending on what logic is running in the program.
Okay, so, that's it,
those are a bunch of examples for stateful lambdas.
Hopefully this stuff makes sense,
there's a lot of other examples
that obviously you can play around with and create yourself.
In the next video we'll wrap up this section
and we'll go over some examples of using lambdas
with the standard template library algorithms,
some simple use cases,
and we'll just kind of pick a bunch of example algorithms
and try them out and show you how that works.