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 toall_data
orfind_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 );