Anonymous Functions (Lambdas)

Table of Contents


1. What are anonymous functions?

Anonymous functions are functions we can define in-line in our code, without giving that function a name. In C#, the LINQ framework allows us to use Lambda functions, and in JavaScript and with JQuery we see anonymous functions used a lot as the result of other functions completing, or a function passed around as a parameter to some other function.

This can be confusing to read without seeing it. In software development, I've usually used these in C# to sort through or search through data to get returned data based on some criteria - without having to write a totally new function. In JQuery, it's common to make a function as a "do this once this other function is done".

2. Anonymous functions in C++

The form of an Anonymous Function in C++ looks like this:

[CAPTURE_CLAUSE] (PARAMETER_LIST) -> RETURN_TYPE {
    FUNCTION_BODY
};

So, for example, if you need to sum two numbers but only inside a specific scope:

int result = []( int a, int b ) {
    return a + b;
}( 1, 2 );

For these next examples, let's say we have a vector<Restaurant> all_data to look through, and a string find_me as the search term. The anonymous functions we define would be inside another function, so let's use a shell function like this:

Empty capture
By doing an empty capture, denoted by empty square brackets [], this means the internal (anonymous) function does not take any variables in the current scope. In this case, it doesn't automatically gain access to all_data or find_me. Instead, we have to specify input parameters as the parameter list and At the end of the anonymous function specification is the function call, where we have to pass in the arguments.
// vector<Restaurant> all_data and
// string find_me are in scope

vector<Restaurant> matchedData = []                   // Capture clause
  ( vector<Restaurant> restaurants, string city )     // Parameter list
  -> vector<Restaurant>                               // Return type
  {                                                   // Function body
    vector<Restaurant> matches;
    for ( auto& r : restaurants )
      {
        if ( r.m_name == name )
          {
            matches.push_back( r );
          }
      }
    return matches;
  }
  ( all_data, find_me );                             // Function call

return matchedData;                   // The matched results will be returned here
Capture variables within scope
In this case, we're capturing the variables within scope using the equal sign within the square brackets, [=]. This means that we don't need to specify a parameter list for any items that are in this scope. Likewise, at the function call step, there is nothing in the parentheses - no arguments being passed in this way.
// vector<Restaurant> all_data and
// string find_me are in scope

vector<Restaurant> matchedData = [=]                  // Capture clause
  ()                                                  // Parameter list
  -> vector<Restaurant>                               // Return type
  {                                                   // Function body
    vector<Restaurant> matches;
    for ( auto& r : restaurants )
      {
        if ( r.m_name == name )
          {
            matches.push_back( r );
          }
      }
    return matches;
  }
  ();                                                 // Function call

return matchedData;                   // The matched results will be returned here
Condensing the anonymous functions

Usually these would be written out much more concisely to take up less space in the code. An example of how this might look in an actual codebase are:

// Print out matches
[]( vector<Restaurant>& data, string search ) -> void {
  for ( auto& d : data )
    {
      if ( d.name.find( search ) != string::npos )
        {
          cout << d.name << endl;
        }
    }
}( all_restaurants, search_term );

Author: Rachel Wil Sha Singh

Created: 2023-10-27 Fri 00:07

Validate