Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is a lambda expression in C++11?

What is a lambda expression in C++11? When would I use one? What class of problem do they solve that wasn't possible prior to their introduction?

A few examples, and use cases would be useful.

like image 584
Nawaz Avatar asked Oct 02 '11 14:10

Nawaz


People also ask

What is lambda expression?

A lambda expression is a short block of code which takes in parameters and returns a value. Lambda expressions are similar to methods, but they do not need a name and they can be implemented right in the body of a method.

Is there lambda function in C?

Significance of Lambda Function in C/C++ Lambda Function − Lambda are functions is an inline function that doesn't require any implementation outside the scope of the main program. Lambda Functions can also be used as a value by the variable to store.

What is a lambda expression example?

Lambda expressions basically express instances of functional interfaces (An interface with single abstract method is called functional interface. An example is java.lang.Runnable). lambda expressions implement the only abstract function and therefore implement functional interfaces.

How do you declare lambda in C++?

Creating a Lambda Expression in C++auto greet = []() { // lambda function body }; Here, [] is called the lambda introducer which denotes the start of the lambda expression. () is called the parameter list which is similar to the () operator of a normal function.


1 Answers

The problem

C++ includes useful generic functions like std::for_each and std::transform, which can be very handy. Unfortunately they can also be quite cumbersome to use, particularly if the functor you would like to apply is unique to the particular function.

#include <algorithm> #include <vector>  namespace {   struct f {     void operator()(int) {       // do something     }   }; }  void func(std::vector<int>& v) {   f f;   std::for_each(v.begin(), v.end(), f); } 

If you only use f once and in that specific place it seems overkill to be writing a whole class just to do something trivial and one off.

In C++03 you might be tempted to write something like the following, to keep the functor local:

void func2(std::vector<int>& v) {   struct {     void operator()(int) {        // do something     }   } f;   std::for_each(v.begin(), v.end(), f); } 

however this is not allowed, f cannot be passed to a template function in C++03.

The new solution

C++11 introduces lambdas allow you to write an inline, anonymous functor to replace the struct f. For small simple examples this can be cleaner to read (it keeps everything in one place) and potentially simpler to maintain, for example in the simplest form:

void func3(std::vector<int>& v) {   std::for_each(v.begin(), v.end(), [](int) { /* do something here*/ }); } 

Lambda functions are just syntactic sugar for anonymous functors.

Return types

In simple cases the return type of the lambda is deduced for you, e.g.:

void func4(std::vector<double>& v) {   std::transform(v.begin(), v.end(), v.begin(),                  [](double d) { return d < 0.00001 ? 0 : d; }                  ); } 

however when you start to write more complex lambdas you will quickly encounter cases where the return type cannot be deduced by the compiler, e.g.:

void func4(std::vector<double>& v) {     std::transform(v.begin(), v.end(), v.begin(),         [](double d) {             if (d < 0.0001) {                 return 0;             } else {                 return d;             }         }); } 

To resolve this you are allowed to explicitly specify a return type for a lambda function, using -> T:

void func4(std::vector<double>& v) {     std::transform(v.begin(), v.end(), v.begin(),         [](double d) -> double {             if (d < 0.0001) {                 return 0;             } else {                 return d;             }         }); } 

"Capturing" variables

So far we've not used anything other than what was passed to the lambda within it, but we can also use other variables, within the lambda. If you want to access other variables you can use the capture clause (the [] of the expression), which has so far been unused in these examples, e.g.:

void func5(std::vector<double>& v, const double& epsilon) {     std::transform(v.begin(), v.end(), v.begin(),         [epsilon](double d) -> double {             if (d < epsilon) {                 return 0;             } else {                 return d;             }         }); } 

You can capture by both reference and value, which you can specify using & and = respectively:

  • [&epsilon, zeta] captures epsilon by reference and zeta by value
  • [&] captures all variables used in the lambda by reference
  • [=] captures all variables used in the lambda by value
  • [&, epsilon] captures all variables used in the lambda by reference but captures epsilon by value
  • [=, &epsilon] captures all variables used in the lambda by value but captures epsilon by reference

The generated operator() is const by default, with the implication that captures will be const when you access them by default. This has the effect that each call with the same input would produce the same result, however you can mark the lambda as mutable to request that the operator() that is produced is not const.

like image 155
Flexo Avatar answered Oct 12 '22 21:10

Flexo