Lambdas and the Standard Library

Packt Publishing
A free video tutorial from Packt Publishing
Tech Knowledge in Motion
3.9 instructor rating • 1420 courses • 349,222 students

Lecture description

Understand how lambdas and the Standard Library interact and benefit from each other

Learn more from the full course

Mastering C++ Standard Library Features

Harness the power of the C++ STL and make full use of its components

06:12:38 of on-demand video • Updated January 2018

  • Analyze and demystify some major new features such as move semantics, variadic templates, and lambdas
  • Learn about new core language features and the problems they were intended to solve
  • Discover new techniques that allow computations to be performed at compile-time
  • Create safer and more convenient interfaces, without any extra hidden cost
  • Improve your code by replacing new/delete with smart pointers
  • Get well versed with the C++ STL and make full use of its components
English [Auto] Mastering lambdas in the section we're going to take a look at lambdas in the standard library and the way they interact with local functions including the idiom. And finally how to use higher order functions to build safer interfaces. Let's begin with the first video lumpers understander library in this video. We're going to take a look at using lambdas with algorithm threat and future and tuple numbers and algorithms interact well together. The center library provides dozens of algorithms that accept one or more functional parameters. Most of them reside in the algorithm Hetter while holders like acidy accumulate Rezaei into numeric header. Such a library provides dozens of algorithms that accept one or more function object parameters. Most of them reside in the algorithm under orders like a CD accumulate reside in a numeric header. Here's a very simple algorithm for each. I've taken a screenshot for CBP reference that shows the various signatures available to the user as you can see for each takes an input iterator as the first name paranoid or as the last. And then you know the function f will be invoked on each element of the range it by the two iterators since he was 17 there was a new overload that accepts execution policy which allows you to automatically paralyze your algorithm. Here's a simple example. I created a vector of integers with 0 1 2 and 3. And then I pass begin V and and on TV and Alamdar paused before each This will invoke there's closure over here on each element inside his range. Since he was 4:17 as I said in the previous slide you will be able to specify an execution policy. You have a sec execution policies par execution policy and an SEC execution policy. The first one tells the algorithm to be run sequentially. This means that it will not make use of any parallelism. The second one means parallel and it will allow the algorithm to be run with multiple fronts. The third one will not only allow the algorithm to run in parallel but will also allow the algorithm to be vectorized. All of these have different guarantees and rules that you should check out before using execution Poesy for algorithms assuming that in this example here something is a function can be called safely by multiple fronts at the same time. Then I can simply add execution par as the first argument to foreach. And this will be paralyzed for me automatically I really like this family of three algorithms all of any of and none of what they do is really self-explanatory. Given a range and a predicate they will return whether or not that predicate satisfies all of the element is the range these algorithms can substitute very very unintuitive loops written to express the idea of oh any or none. So take a look at some examples. Imagine that we have a struct called Person which contains a name and an age and a vector of person called P.S. We want to know whether or not all the people inside the vector have reached the legal age to drink. We can't say something like can spoof can drink equals Asadi all of the range of p s and Islam here will return whether or not the age of some person is greater when I'm 21. These are very intuitive and terse way of checking whether a predicate is a placable for every element inside the container. Now imagine that we getting the data for people from some surveys and we might have some missing data for the names you want to check whether or not all the people in the vector have names. We might say something along the lines of Asadi none of using Parlow and sequence execution policy. The range of the vector and the spreading it over here which returns whether or not the name of P is empty and we can read these as old people have names if none of the people inside the vector have an empty name which is really intuitive and powerful order of two very useful algorithms are a city county and city county if count in this case simply takes a value to compare to and we'll return the amount of occurrences that that value appears inside the Orange County. On the other hand takes a predicate and it will return the amount of occurrences an element inside the range satisfies the predicate. There is a great opportunity to use Alamdar. Imagine you're writing some sort of game where players have a level and you want to run some statistics and see how many of your players have reached the high level of 70. You can simply say something like a city county of beginning players and the players and then a predicate that will determine whether or not P has reached level 70. This kind of terse and intuitive code is made possible thanks lambda expressions Dyess algorithm there should be. In my opinion use more often is a silly partition. Given a range and a predicate it will shift around elements inside the range to bring all those elements satisfying the predicate on one side and all the elements not satisfy the predicate. On the other side. Here's an example. Imagine that we have a system where we have string IDs and IDs referring to users beginning with the dot notation and IDs referring to groups. Begin with a G dot notation and let's say that we have an heterogeneous set of IDs and we want to partition it so that all the users are left side in all the groups on the right side. We might invoke the partition as follows. First we passed the begin and the end of a range and then we provide a predicate that checks that the first two characters of the string are you and not what we get back is an iterator I-T which represent the splitting point. If you use a CD for each. From the beginning of the 80s to da t we can print out all the user IDs and if we use it again from I-T to the end of IBS we'll can print out all the group. Another very powerful algorithm is a city Max element given our range and a predicate given our range and our comparison function. You will find the maximum element with respect to the comparison function inside the range and return an iterator to it. Here's an example. Imagine that we have a vector of music tracks and we want to find the longest song. All we can do is get the max element with the beginning of songs and songs and then provide a comparison Lamda gets sungei and song B and simple returns the comparison of the direction. This will return an iterator pointing to the longest song in the vector. The takeaway here is that any algorithm that makes a function object or a colorable as a parameter can benefit from lambda expressions. Your code can become more expressive and shorter since it was posted 17. You also have morphisms as use algorithms as they can be automatically parallelize thanks to execution policy. If you want to see a very nice reference for the algorithm header and the numeric header. As always I recommend the CPV reference pages which are very Torro and very informative. It does not take a look at how lambdas can up with multi-threading since that is 11 in the center library provides a lot of useful multi-threading facilities. I said this thread is the basic facility that represents a threat of execution and it allows the creation of a thread that executes a given callable object. In this case I'm creating a new thread. Passing a lambda as its argument which will sleep for 100 milliseconds and then print out world after reading the thread. I immediately print out hello and then join to wait for the thread to finish. This will print out Hello world as the thread will sleep and will leave the first out call a chance to be executed. Does make it easy to invoke member functions of synchronicity as well. Imagine that we have my foo object of type Foo which provides the zero and if one member functions and we want to run both of them at the same time I synchronously in separate threads. All we can do is use a lambda to capture the instance of foo. Pass it to a thread invoking my food not at 0 or 1 and then do something while this is run in the background and finally join the threads to wait for them to finish. Another really useful utility introduced in service policy 11 with regard to multi-threading is a city future. It takes a template parameter T and allows us to synchronously compute an instance of t and get it later in the future. You can think of it as a promise that will give you an instance of T later in the solution of the problem. If you have some sort of long running computation you can simply invoke a function that returns a future to it and what is running in the background on some other thread. You can do other things and then you will be able to get the results later in your code. Instances of a city future that run in separate threads can be spawned by using a CD a sync which is an on the library facility. In this case. In order to guarantee that a separate thread will be used you need to use the acidy launch as seen policy Saigo because some examples are a basic way of creating a future for us. The thing is simply creating a variable and initializing it with the return value of the same call. In this case I'm using the async policy to make sure it will start another thread in the body. I'm sleeping for one second and then returning a value. While it is running in the background I can do something else. And then finally I can assert that after I get is 42 in use case after get will immediately return. If the computation was completed by the time I ended up here. Otherwise it will block and wait until the computation is completed. Most future and soon I see the future Rosewell will allow sinking into consideration to be changed by using dot down when all or when any. This allows you to create. This allows you to define graphs of synchronous computations that might depend on each other which will execute in parallel one possible in this case. I'm using Boosey sync to lunch. Some time I'll get requests of some URL and then using the dot then member function. I'm changing another operation by using Alamdar that takes the previous future as an argument and provides a subsequent computation to execute. There is another utility called boost when all that. Given any amount of fut. in this case with async it will execute them in parallel and only when all of them are finished. It will then continue on to the continuation. So as you can see you can create some sort of really complicated pipeline where you have multiple things depending on each other but you will always try to execute as many things in Perl as possible. Respect depends. In this case I'm simulating to get requests in parallel to different you or else. And then when both of them are done I will get back a future representing the finished computation of part of them and then I can use it to continue my computation later on the program. So look at how lambdas interact with tuples a city tuple of TS is a fixed size collection of indigenous values. As an example you can say use tuple of int float and char T and initialize it with an int float and a char and this will basically store them as if they were in a struct Lander's can help us here. Invoke an existing function objects with the elements of the tuple or iterate over a tuples elements. Notice that it does we need this new great utility introduced in 2010 called a city apply apply takes a function and a tuple and it will invoke the function by unpacking the Armand's inside a tuple. Here's a very simple example. If you have a tuple containing two N's zero that contains 1 and 3 then we can use this apply to invoke Alamdar. Taking two ends bypassing the tuple. Second argument apply. We'll unpack the one for us and pass them as the argument of provide a lambda which in this case will simply return to some of the arguments if we use this you apply on to zero and this is Lamda we will get back four which is the sum of one plus three. Make it easy to extract some functionality and apply that to other tuples what we can do is create this new some Lamda that takes a tuple and then returns Asadi apply of the previous lambda and the Teter were taken as an argument. In this case we don't have to bundle the logic that we want to execute in the same place as we have the tuple. We want to call the function with but we can simply say some with a tuple and get back the result we expect. In this case the that is allowing us to bind this lambda here as the first argument of Asadi apply and then generalize it over the tuple parameter by combining lambdas and sippers and in full expressions we can easily iterate over tuples elements and by iterate I mean generate code that will be executed for each element of the tuple as a tuple is a true genius compile time construct which kind of be Rayder upon runtime. In this case I have a tuple of Vinton char where my end is 42 and Machar's uppercase X and they invoke ISDE apply bypassing lambda. That takes very the amount of arguments and the tuple. What will happen is that this slummed will be invoked to 42 and X and now a museum 17 fold expression that will stream all the elements inside the access parameter pack to ACTC out. If you're not familiar with the syntax This basically means to expand every element contained inside this pack as part of this trimming operation. The final result is 42 x. Think about it this way we can model iteration over the elements of a tuple as we are executing a particular operation on every single element contained inside it. We can generalize this again by using lambdas we can create this construct called for tuple. That takes a function and a tuple and calls a city apply for us by providing a variadic lambda which takes all the elements inside the tuple. Forwarded here to acidy apply. And then again uses another C++ of in-thing fold expression to invoke F on every single element of the tuple perfectly forward. In this case we can say something like the tuple of int and char with the previous values and instead of explicitly using all the expressions that apply we can use for tuple with a lambda that takes an element of the tuple and simply printed out the CDC out using these outer construct allows us to for example provide a separator between the moments of the tuple. Note how four tuple is basically CD4 each. But for two elements and also note how we're using auto in this example because we need to make sure we can handle all the different types contain said a tuple. Here's a quick recap for this video. Most algorithms in the standard library greatly benefit from some expressions. This allows you to make your code more expressive shorter and way more intuitive. Spawning threats and futures. This is also an intuitive way of creating a synchronous computations combining lambdas and Asadi apply allows us to easily manipulate Su's tuple elements and create some very useful utilities and obstructions allow us to either call a function with elements or iterate over them by generating code for each element. Here's my guidelines. Unless you have a very commonly used or long predicate always prefer lambdas instead of structure or nonmember functions for algorithms for simple synchronous computations. Prefer in place numbers Mark complicated pipelines will benefit from having named function objects. This could be lambdas themselves or thrax are no member functions but I strongly suggest you to bind them to some name either with a variable or with normal function syntax in order to make your synchronous computation more composable and easier to understand. Also here are some references about support for 17 and the new feature instead of 17. And this great book by Anthony Williams. First concurrency in action which gives you a very very thorough overview of the simplest possible on multi-threading facilities and a lot of realistic use case examples. The next video will still be going to look at how all of those came through our code by seeing how they can be used as local functions.