Sunday, December 29, 2024

lambda expression

Overview
A functor or function objects is an object or structure that can be called like a function by overloading the function call  

Details
Lambdas are basically anonymous function objects generated right at the location where it's invoked or passed as an argument to a function. Lambdas are game changer since they seamlessly integrate into stl algorithms, concurrency objects and more. 
The syntax for Lambdas is as below.

[capture] (parameters)optional mutableoptional exception-Specoptional -> trailing return Typeoptional
{
    definition of method
}

Except for the lambda introducer ([]) that contain captured local variables, all of the other  items in the syntax are optional.

Following is a minimum lambda expression, calling itself.
[] //introducer
   // no parameters
{
    time_t curr_time;
    curr_time = time(NULL);

    tm *tm_local = localtime(&curr_time);
    size_t h = tm_local->tm_hour;
    cout << "Hello, ";

    if (h > 4 && h < 12)
        cout << "Good Morning";
    else if (h > 11 && h < 17)
        cout << "Good Afternoon";
    else if (h > 16 )
         cout << "Good Evening";
    cout << "!" << endl;

}   //body
(); //calling itself! 
//prints @ 3 am : Hello, Good Evening!

The following describes it in detail:
  1. capture clause (Also known as the lambda-introducer)
  2. parameters  (Also known as the lambda declarator)
  3. mutable specification.
  4. exception-specification.
  5. trailing-return-type.
  6. lambda definition.
capture
Unlike a normal function, a lambda can also to refer to local variables. It can access them either as read only value or as a reference as described below.
  • [=]  captures all local variables as value readonly
  • [&]  captures all local variables as value readwrite
  • [i,j,&k] captures local variables i and j as value readonly and k as value readwrite
  • [=,&i] captures all local variables as value readonly except i
  • [&,=i]  captures all local variables as value readwrite except i
  • [this] captures all local variables as value readonly
  • [v...] captures variadic variables
If the captured variables are modified, value captured variables do not retain modified value and revert back to original after the call; reference captured variables retain modified values after the call. 
Global variables and static variables need not be captured. They can be accessed as is.
This is demonstrated in the example 2

parameters
Parameters for a lambda are similar to those of normal functions, 
This is depicted in the example 3.

mutable 
This keyword should be used if value captured variables are modified in the implementation. 
This is demonstrated in the example 2

exception specification
noexcept exception specification can be used  to indicate that the lambda expression doesn't throw any exceptions. As with ordinary functions, the compiler generates warning if a lambda expression declares the noexcept exception specification and the lambda body throws an exception.
    //compiler warnings
    []() noexcept { throw 5; }();

trailing return type
The return type for a lambda is specified using a C++ feature named trailing return type. This specification is optional. Without the trailing return type, the return type of the underlying function is effectively auto, and it is deduced from the type of the expressions in the body's return statements.
This is depicted in the example 4.

Lambda in action
Following are some examples where lambdas can be used in stl and concurrency.
This is depicted in the example 5.

The following example demonstrates usage of recursive lambda expression. note auto cannot be used to store lambda expression.
function<void(int)> fib = [t1=0, t2 = 1,t=0]  (int n) mutable
{
    if (n>0)
    {
        cout << t1 << " ";
        t = t2;
        t2 += t1;
        t1 = t;
        fib(n-1);
    }
    else
        cout << " = " << t1 ; 
};
fib(5); //0 1 1 2 3 = 7
fib(9); //0 1 1 2 3 5 8 13 21 = 54  

Summary of Examples
NameDescriptiongithubwandbox
  Example       Generic Functor  source    output    source + output 
  Example 2       Lambda - Capture and mutable  source    output    source + output 
  Example 3Lambda - Parameters  source    output  source + output 
  Example 4Lambda - Trailing return type  source    output  source + output  
  Example 5Lambda - in Action  source    output  source + output  
  Example 6Predefined functors  source    output  source + output 



No comments:

Post a Comment