int num[7] = { 45,6,3,32,5,53,12 }

sort(nums, nums+7, [ ] (int a , int b) {return a > b ; } );

Anonymous function

It allows a function to be defined at the point where it’s needed in another expression

A lambda expression can have more power than an ordinary function by having access to variables from the enclosing scope

lambda template

[] :  lambda introducer which denotes the start of the lambda expression

() : parameter list which is similar to the () operator of a normal function

captures

Params : the list of parameters as in named functions

specs (optional)
-specifiers : (mutable (C++11), constexpr(C++17), consteval(C++20), static(C++23) )
-trailing-return-type : -> ret, where ret specifies the return type

body : function body


Closure type (unnamed nonunion class type)

“The distinction between a lambda and the corresponding closure is precisely equivalent

to the distinction between a class and an instance of the class <effective modern c++>”

 

sample code 1

int num[7] = { 45,6,3,32,5,53,12}

sort(nums, nums+7, [ ] (int a , int b) {return a > b ; } );

sample code 2

class ClosureType{
   public:
       bool operator( )(int a , int b) const {
                  return a > b ;
        }
};


sort(nums, nums+7,  ClosureType() );

 

sample code 3

int main()
{
   [ ] (int a , int b) { return a > b; } (12, 24) ;
   auto l = [ ] (int a , int b) { return a > b; } ;
   cout << l (55,33) <<endl;
}

Type of lambda

The type of the lambda-expression (which is also the type of the closure object) is a unique

 

auto l = [ ](int a, int b) { return a * b } ;

auto l2 = [ ](int a, int b) { return a * b } ;

cout<<typeid(l).name()<<endl;

cout<<typeid(l2).name()<<endl;

 


Inline replacement

 

sample code 4

auto lambda = [ ](int a, int b) { return a * b } ;                   //  inline replacement - O
int (*fp)(int, int) = [ ](int a, int b) { return a * b };            //  inline replacement - X
function<int(int, int) > func = [ ](int a , int b) { return a* b; }; //  inline replacement - X

lambda = [ ](int a, int b) { return a + b } ;  //error
fp = [ ](int a, int b) { return a + b };
func =  [ ](int a , int b) { return a - b; };

Passing lambda function as arguments

1) function pointer or std::function object

 

sample code 5

typedef int (*fp)(int, int);
void foo(fp f)
{
    f(12, 24);
}

int main()
{
    foo( [ ] (int a , int b) { return a * b ; } );   
    foo( [ ] (int a , int b) { return a * b ; } );
}

 

2) template declaration

 

sample code 6

template<typename T>
void foo(T f)
{
    f(12, 24);
}

int main()
{
    foo( [ ] (int a , int b) { return a * b ; } );   
    foo( [ ] (int a , int b) { return a * b ; } );
}

Return type

The compiler can implicitly deduce the return type of the lambda expression based on the return statement

But for multiple return statements of different types, we have to explicitly define the type valuation

 

sample code 7

auto  f2 = [ ](int a , int b) { 
                       if(a% 2) {
                             return a;
                        }else{
                             return b;
                        }  }

 

sample code 8

auto  f2 = [ ] -> double (int a , double b) { 
                       if(a% 2) {
                             return a;
                        }else{
                             return b;
                        }  }

Capture

By default, lambda functions cannot access variables of the enclosing function

In order to access those variables, we use the capture clause.

 

Capture by value

- Basic expression:  [data] (..) { … }

- The actual value is copied when the lambda is created.

- we can only read the variable inside the lambda body but cannot modify it.

- [=] says all the variables of the enclosing function are captured by value.

 

Capture by reference

- Basic expression:  [&data] (..) { … }

- The lambda has access to the variable address.

- we can read the variable as well as modify it inside the lambda body.

- [&] indicates that all the variables are captured by reference

 

sample code 9

int gVal = 100;   // global variable
int main() 
{ 
   int val1 = 20; 
   int val2 = 30; 
   auto f1 = [ ](int a) { gVal = 10; return a + gVal; }; 
   auto f2 = [ ](int a) { return a + val1; };    // error
   auto f3 = [val1](int a) { return a + val1; }; 
   auto f4 = [val1, val2](int a) { return a + val1 + val2; }; 
   auto f5 = [val1](int a) { val1 = 2; return a + val1; }; // error  
   auto f6 = [val1](int a) mutable { val1 = 2; return a + val1; };  
}

 

sample code 10

class ClosureType{
   public:
       ClosureType(int a): val1(a)
       bool operator( )(int a) const {
                  val1 = 2;
                  return a + val1 ;
        }
    private:
        int val1;
};

 

sample code 11

int main( ) 
{ 
   int val1 = 20; 
   int val2 = 30; 
    auto f = [val1, val2]( ) { return val1 + val2; };

    auto f2 = [ ] () { return true; };

    cout<< sizeof(f) << “,” <<sizeof(f2) << endl; 
}

 

sample code 12

class ClosureType{
  public:
       ClosureType(int a, int b): val1(a), val2(b) { }
       bool operator( )( ) const {
                  return val1 + val2 ;
        }
 private:
       int val1;
       int val2;
};

 

sample code 13

int main()
{   
    int val1 = 0; 
    int val2 = 10;
    int val3 = 100; 

    auto f1 = [val1]( ) { };
    auto f2 = [&val2 ] ( ) { };
    auto f3 = [val1, &val2 ] ( ) { };
    auto f4 = [=] () { };
    auto f5 = [&] () { };
    auto f6 = [=, &val1] () { };   
    auto f7 = [&, val1] () { };     
    auto f8 = [=, val1] () { };
    
    auto f9 = [ a = val1, val2 = val2, val3] ( ) { } ;
    auto f10 = [  val1, b = val2, &r = val3] ( ) { } ;

	std::string s  = “hello world”;
	auto f11 = [ d = move(s) ] () {cout<<d<<endl; } ;
	cout<< s << endl; 
	f11();

}

unique_ptr

+ Recent posts