[c++] 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.

This question is related to c++ lambda c++11 c++-faq

The answer is


A lambda function is an anonymous function that you create in-line. It can capture variables as some have explained, (e.g. http://www.stroustrup.com/C++11FAQ.html#lambda) but there are some limitations. For example, if there's a callback interface like this,

void apply(void (*f)(int)) {
    f(10);
    f(20);
    f(30);
}

you can write a function on the spot to use it like the one passed to apply below:

int col=0;
void output() {
    apply([](int data) {
        cout << data << ((++col % 10) ? ' ' : '\n');
    });
}

But you can't do this:

void output(int n) {
    int col=0;
    apply([&col,n](int data) {
        cout << data << ((++col % 10) ? ' ' : '\n');
    });
}

because of limitations in the C++11 standard. If you want to use captures, you have to rely on the library and

#include <functional> 

(or some other STL library like algorithm to get it indirectly) and then work with std::function instead of passing normal functions as parameters like this:

#include <functional>
void apply(std::function<void(int)> f) {
    f(10);
    f(20);
    f(30);
}
void output(int width) {
    int col;
    apply([width,&col](int data) {
        cout << data << ((++col % width) ? ' ' : '\n');
    });
}

Lambda expressions are typically used to encapsulate algorithms so that they can be passed to another function. However, it is possible to execute a lambda immediately upon definition:

[&](){ ...your code... }(); // immediately executed lambda expression

is functionally equivalent to

{ ...your code... } // simple code block

This makes lambda expressions a powerful tool for refactoring complex functions. You start by wrapping a code section in a lambda function as shown above. The process of explicit parameterization can then be performed gradually with intermediate testing after each step. Once you have the code-block fully parameterized (as demonstrated by the removal of the &), you can move the code to an external location and make it a normal function.

Similarly, you can use lambda expressions to initialize variables based on the result of an algorithm...

int a = []( int b ){ int r=1; while (b>0) r*=b--; return r; }(5); // 5!

As a way of partitioning your program logic, you might even find it useful to pass a lambda expression as an argument to another lambda expression...

[&]( std::function<void()> algorithm ) // wrapper section
   {
   ...your wrapper code...
   algorithm();
   ...your wrapper code...
   }
([&]() // algorithm section
   {
   ...your algorithm code...
   });

Lambda expressions also let you create named nested functions, which can be a convenient way of avoiding duplicate logic. Using named lambdas also tends to be a little easier on the eyes (compared to anonymous inline lambdas) when passing a non-trivial function as a parameter to another function. Note: don't forget the semicolon after the closing curly brace.

auto algorithm = [&]( double x, double m, double b ) -> double
   {
   return m*x+b;
   };

int a=algorithm(1,2,3), b=algorithm(4,5,6);

If subsequent profiling reveals significant initialization overhead for the function object, you might choose to rewrite this as a normal function.


One problem it solves: Code simpler than lambda for a call in constructor that uses an output parameter function for initializing a const member

You can initialize a const member of your class, with a call to a function that sets its value by giving back its output as an output parameter.


The lambda's in c++ are treated as "on the go available function". yes its literally on the go, you define it; use it; and as the parent function scope finishes the lambda function is gone.

c++ introduced it in c++ 11 and everyone started using it like at every possible place. the example and what is lambda can be find here https://en.cppreference.com/w/cpp/language/lambda

i will describe which is not there but essential to know for every c++ programmer

Lambda is not meant to use everywhere and every function cannot be replaced with lambda. It's also not the fastest one compare to normal function. because it has some overhead which need to be handled by lambda.

it will surely help in reducing number of lines in some cases. it can be basically used for the section of code, which is getting called in same function one or more time and that piece of code is not needed anywhere else so that you can create standalone function for it.

Below is the basic example of lambda and what happens in background.

User code:

int main()
{
  // Lambda & auto
  int member=10;
  auto endGame = [=](int a, int b){ return a+b+member;};

  endGame(4,5);

  return 0;

}

How compile expands it:

int main()
{
  int member = 10;

  class __lambda_6_18
  {
    int member;
    public: 
    inline /*constexpr */ int operator()(int a, int b) const
    {
      return a + b + member;
    }

    public: __lambda_6_18(int _member)
    : member{_member}
    {}

  };

  __lambda_6_18 endGame = __lambda_6_18{member};
  endGame.operator()(4, 5);

  return 0;
}

so as you can see, what kind of overhead it adds when you use it. so its not good idea to use them everywhere. it can be used at places where they are applicable.


One of the best explanation of lambda expression is given from author of C++ Bjarne Stroustrup in his book ***The C++ Programming Language*** chapter 11 (ISBN-13: 978-0321563842):

What is a lambda expression?

A lambda expression, sometimes also referred to as a lambda function or (strictly speaking incorrectly, but colloquially) as a lambda, is a simplified notation for defining and using an anonymous function object. Instead of defining a named class with an operator(), later making an object of that class, and finally invoking it, we can use a shorthand.

When would I use one?

This is particularly useful when we want to pass an operation as an argument to an algorithm. In the context of graphical user interfaces (and elsewhere), such operations are often referred to as callbacks.

What class of problem do they solve that wasn't possible prior to their introduction?

Here i guess every action done with lambda expression can be solved without them, but with much more code and much bigger complexity. Lambda expression this is the way of optimization for your code and a way of making it more attractive. As sad by Stroustup :

effective ways of optimizing

Some examples

via lambda expression

void print_modulo(const vector<int>& v, ostream& os, int m) // output v[i] to os if v[i]%m==0
{
    for_each(begin(v),end(v),
        [&os,m](int x) { 
           if (x%m==0) os << x << '\n';
         });
}

or via function

class Modulo_print {
         ostream& os; // members to hold the capture list int m;
     public:
         Modulo_print(ostream& s, int mm) :os(s), m(mm) {} 
         void operator()(int x) const
           { 
             if (x%m==0) os << x << '\n'; 
           }
};

or even

void print_modulo(const vector<int>& v, ostream& os, int m) 
     // output v[i] to os if v[i]%m==0
{
    class Modulo_print {
        ostream& os; // members to hold the capture list
        int m; 
        public:
           Modulo_print (ostream& s, int mm) :os(s), m(mm) {}
           void operator()(int x) const
           { 
               if (x%m==0) os << x << '\n';
           }
     };
     for_each(begin(v),end(v),Modulo_print{os,m}); 
}

if u need u can name lambda expression like below:

void print_modulo(const vector<int>& v, ostream& os, int m)
    // output v[i] to os if v[i]%m==0
{
      auto Modulo_print = [&os,m] (int x) { if (x%m==0) os << x << '\n'; };
      for_each(begin(v),end(v),Modulo_print);
 }

Or assume another simple sample

void TestFunctions::simpleLambda() {
    bool sensitive = true;
    std::vector<int> v = std::vector<int>({1,33,3,4,5,6,7});

    sort(v.begin(),v.end(),
         [sensitive](int x, int y) {
             printf("\n%i\n",  x < y);
             return sensitive ? x < y : abs(x) < abs(y);
         });


    printf("sorted");
    for_each(v.begin(), v.end(),
             [](int x) {
                 printf("x - %i;", x);
             }
             );
}

will generate next

0

1

0

1

0

1

0

1

0

1

0 sortedx - 1;x - 3;x - 4;x - 5;x - 6;x - 7;x - 33;

[] - this is capture list or lambda introducer: if lambdas require no access to their local environment we can use it.

Quote from book:

The first character of a lambda expression is always [. A lambda introducer can take various forms:

[]: an empty capture list. This implies that no local names from the surrounding context can be used in the lambda body. For such lambda expressions, data is obtained from arguments or from nonlocal variables.

[&]: implicitly capture by reference. All local names can be used. All local variables are accessed by reference.

[=]: implicitly capture by value. All local names can be used. All names refer to copies of the local variables taken at the point of call of the lambda expression.

[capture-list]: explicit capture; the capture-list is the list of names of local variables to be captured (i.e., stored in the object) by reference or by value. Variables with names preceded by & are captured by reference. Other variables are captured by value. A capture list can also contain this and names followed by ... as elements.

[&, capture-list]: implicitly capture by reference all local variables with names not men- tioned in the list. The capture list can contain this. Listed names cannot be preceded by &. Variables named in the capture list are captured by value.

[=, capture-list]: implicitly capture by value all local variables with names not mentioned in the list. The capture list cannot contain this. The listed names must be preceded by &. Vari- ables named in the capture list are captured by reference.

Note that a local name preceded by & is always captured by reference and a local name not pre- ceded by & is always captured by value. Only capture by reference allows modification of variables in the calling environment.

Additional

Lambda expression format

enter image description here

Additional references:


Answers

Q: What is a lambda expression in C++11?

A: Under the hood, it is the object of an autogenerated class with overloading operator() const. Such object is called closure and created by compiler. This 'closure' concept is near with the bind concept from C++11. But lambdas typically generate better code. And calls through closures allow full inlining.

Q: When would I use one?

A: To define "simple and small logic" and ask compiler perform generation from previous question. You give a compiler some expressions which you want to be inside operator(). All other stuff compiler will generate to you.

Q: What class of problem do they solve that wasn't possible prior to their introduction?

A: It is some kind of syntax sugar like operators overloading instead of functions for custom add, subrtact operations...But it save more lines of unneeded code to wrap 1-3 lines of real logic to some classes, and etc.! Some engineers think that if the number of lines is smaller then there is a less chance to make errors in it (I'm also think so)

Example of usage

auto x = [=](int arg1){printf("%i", arg1); };
void(*f)(int) = x;
f(1);
x(1);

Extras about lambdas, not covered by question. Ignore this section if you're not interest

1. Captured values. What you can to capture

1.1. You can reference to a variable with static storage duration in lambdas. They all are captured.

1.2. You can use lambda for capture values "by value". In such case captured vars will be copied to the function object (closure).

[captureVar1,captureVar2](int arg1){}

1.3. You can capture be reference. & -- in this context mean reference, not pointers.

   [&captureVar1,&captureVar2](int arg1){}

1.4. It exists notation to capture all non-static vars by value, or by reference

  [=](int arg1){} // capture all not-static vars by value

  [&](int arg1){} // capture all not-static vars by reference

1.5. It exists notation to capture all non-static vars by value, or by reference and specify smth. more. Examples: Capture all not-static vars by value, but by reference capture Param2

[=,&Param2](int arg1){} 

Capture all not-static vars by reference, but by value capture Param2

[&,Param2](int arg1){} 

2. Return type deduction

2.1. Lambda return type can be deduced if lambda is one expression. Or you can explicitly specify it.

[=](int arg1)->trailing_return_type{return trailing_return_type();}

If lambda has more then one expression, then return type must be specified via trailing return type. Also, similar syntax can be applied to auto functions and member-functions

3. Captured values. What you can not capture

3.1. You can capture only local vars, not member variable of the object.

4. ?onversions

4.1 !! Lambda is not a function pointer and it is not an anonymous function, but capture-less lambdas can be implicitly converted to a function pointer.

p.s.

  1. More about lambda grammar information can be found in Working draft for Programming Language C++ #337, 2012-01-16, 5.1.2. Lambda Expressions, p.88

  2. In C++14 the extra feature which has named as "init capture" have been added. It allow to perform arbitarily declaration of closure data members:

    auto toFloat = [](int value) { return float(value);};
    auto interpolate = [min = toFloat(0), max = toFloat(255)](int value)->float { return (value - min) / (max - min);};
    

What is a lambda function?

The C++ concept of a lambda function originates in the lambda calculus and functional programming. A lambda is an unnamed function that is useful (in actual programming, not theory) for short snippets of code that are impossible to reuse and are not worth naming.

In C++ a lambda function is defined like this

[]() { } // barebone lambda

or in all its glory

[]() mutable -> T { } // T is the return type, still lacking throw()

[] is the capture list, () the argument list and {} the function body.

The capture list

The capture list defines what from the outside of the lambda should be available inside the function body and how. It can be either:

  1. a value: [x]
  2. a reference [&x]
  3. any variable currently in scope by reference [&]
  4. same as 3, but by value [=]

You can mix any of the above in a comma separated list [x, &y].

The argument list

The argument list is the same as in any other C++ function.

The function body

The code that will be executed when the lambda is actually called.

Return type deduction

If a lambda has only one return statement, the return type can be omitted and has the implicit type of decltype(return_statement).

Mutable

If a lambda is marked mutable (e.g. []() mutable { }) it is allowed to mutate the values that have been captured by value.

Use cases

The library defined by the ISO standard benefits heavily from lambdas and raises the usability several bars as now users don't have to clutter their code with small functors in some accessible scope.

C++14

In C++14 lambdas have been extended by various proposals.

Initialized Lambda Captures

An element of the capture list can now be initialized with =. This allows renaming of variables and to capture by moving. An example taken from the standard:

int x = 4;
auto y = [&r = x, x = x+1]()->int {
            r += 2;
            return x+2;
         }();  // Updates ::x to 6, and initializes y to 7.

and one taken from Wikipedia showing how to capture with std::move:

auto ptr = std::make_unique<int>(10); // See below for std::make_unique
auto lambda = [ptr = std::move(ptr)] {return *ptr;};

Generic Lambdas

Lambdas can now be generic (auto would be equivalent to T here if T were a type template argument somewhere in the surrounding scope):

auto lambda = [](auto x, auto y) {return x + y;};

Improved Return Type Deduction

C++14 allows deduced return types for every function and does not restrict it to functions of the form return expression;. This is also extended to lambdas.


Well, one practical use I've found out is reducing boiler plate code. For example:

void process_z_vec(vector<int>& vec)
{
  auto print_2d = [](const vector<int>& board, int bsize)
  {
    for(int i = 0; i<bsize; i++)
    {
      for(int j=0; j<bsize; j++)
      {
        cout << board[bsize*i+j] << " ";
      }
      cout << "\n";
    }
  };
  // Do sth with the vec.
  print_2d(vec,x_size);
  // Do sth else with the vec.
  print_2d(vec,y_size);
  //... 
}

Without lambda, you may need to do something for different bsize cases. Of course you could create a function but what if you want to limit the usage within the scope of the soul user function? the nature of lambda fulfills this requirement and I use it for that case.


Examples related to c++

Method Call Chaining; returning a pointer vs a reference? How can I tell if an algorithm is efficient? Difference between opening a file in binary vs text How can compare-and-swap be used for a wait-free mutual exclusion for any shared data structure? Install Qt on Ubuntu #include errors detected in vscode Cannot open include file: 'stdio.h' - Visual Studio Community 2017 - C++ Error How to fix the error "Windows SDK version 8.1" was not found? Visual Studio 2017 errors on standard headers How do I check if a Key is pressed on C++

Examples related to lambda

Java 8 optional: ifPresent return object orElseThrow exception How to properly apply a lambda function into a pandas data frame column What are functional interfaces used for in Java 8? Java 8 lambda get and remove element from list Variable used in lambda expression should be final or effectively final Filter values only if not null using lambda in Java8 forEach loop Java 8 for Map entry set Java 8 Lambda Stream forEach with multiple statements Java 8 stream map to list of keys sorted by values Task.Run with Parameter(s)?

Examples related to c++11

Remove from the beginning of std::vector Converting std::__cxx11::string to std::string What exactly is std::atomic? C++ How do I convert a std::chrono::time_point to long and back Passing capturing lambda as function pointer undefined reference to 'std::cout' Is it possible to use std::string in a constexpr? How does #include <bits/stdc++.h> work in C++? error::make_unique is not a member of ‘std’ no match for ‘operator<<’ in ‘std::operator

Examples related to c++-faq

What are the new features in C++17? Why should I use a pointer rather than the object itself? Why is enum class preferred over plain enum? gcc/g++: "No such file or directory" What is an undefined reference/unresolved external symbol error and how do I fix it? When is std::weak_ptr useful? What XML parser should I use in C++? What is a lambda expression in C++11? Why should C++ programmers minimize use of 'new'? Iterator invalidation rules