Breaking a complex problem into smaller chunks has obvious advantages and this true with functions as it is with design. However, sanity turns into insanity when the sheer number of such small function tends to be overwhelming. In addition, the boilerplate code needed to use these functions such as a functor, tend to slow you down considerably.
Would it not be nice if there were a way to create functions easily on the fly at the point of call?
Lambda expressions are supported in VS2010 SP1 & GCC 4.5 onwards
As has been the tradition let’s start with hello lambda:
The highlighted piece of code is a lambda function definition. An astute user would notice that it is similar to a functor definition:
Lambda Expression Anatomy
A lambda expression can access any variable that has automatic storage duration and that can be accessed in the enclosing scope. The capture clause specifies whether the body of the lambda expression accesses variables in the enclosing scope by value or by reference: variables that have the ampersand (
&) prefix are accessed by reference and variables that do not have the
& prefix are accessed by value. The empty capture clause,
, indicates that the body of the lambda expression accesses no variables from the enclosing scope.
A variable is explicitly captured if it appears in capture clause, else it is implicitly captured. The body of lambda uses the default capture mode to access variables that are implicitly captured.
Parameter list for lambda is same as that for any function but with few constraints:
- No default arguments
- No variable length arguments
- No unnamed parameters
Parameter list for lambdas is optional if you are not going to pass-in any parameter, but keeping it there ensures sane code.
It enables the function body to modify the values that have been captured by values. It is optional.
As with functions you can have exception specifications with lambdas, I would recommend not using them, but it’s really your call whether you want them. It is optional.
Return type for lambda is specified by -> return_type, it is optional only if lambda body contains exactly one statement. However it is good practice to specify return types.
It’s just like regular function body, can contain anything that an ordinary function would contain; you can define nested lambda expressions as well. Lambda expression can access:
- Parameters from parameter list
- Captured variables from enclosing scope
- Class data members, when defined inside a class (behaves like a member function)
- Any global variables
Generic lambdas are now supported with C++17
Lambdas all the way
Lambda – currying, captures
In hello world example lambda did not referred to any variable, thus its capture clause was empty. Capture clause is really powerful, flexible as it lets you capture on variables from enclosing scope and is the most important factor for lambda’s coolness. Let’s see a contrived example where you have been given an array of numbers and have been asked to find if some number exists in it. Here is the first take, off course we will use STL, let’s assume we are looking for number 10:
This works, but is not flexible; we will have to code comparator for each number that we want to find. Second approach is to make comparator take two double values but we still want to use STL:
find_if function takes predicate, here comparator object, which takes only one parameter but our Comparator takes 2 parameters, for flexibility. Somehow we need to convert this comparator to take only 1 parameter. This is where
bind1st comes into picture, what it does is it creates a wrapper functor taking 1 parameter, and binds 1st argument of
comparator to the specified value. Note for this to work you must derive
binary_function. You can imagine how tedious this will become when your comparator takes 3 or more parameters.
Binder were first shot at introducing some kind of closure (variable capturing) support with STL. There are quite a few examples and libraries, like Boost.Lambda and FC++ for higher order function programming, however lambda expressions are coolest as they are language feature. Well this is how the above code will look with lambda:
This is so elegant to code. No need to write boiler-plate functors just to enable such semantics.
Lambda – inside a member function
As discussed earlier, you can define lambdas in member function and they will act as if they were member functions! Here is another contrived Sample class that calculates hypotenuse of array of numbers using lambda:
In this class,
evaluate is the lambda expression, it captures
this by value and
y by reference. Lines 68-69 demonstrate anonymous function; the function being passed to
ApplyToAll is un-named function.
Few observations related to usage of lambdas in member functions:
- They mimic member functions, but are not member functions
- They cannot be defined virtual, so can’t be overridden
- Lambda defined in const function cannot mutate, or change, any member variable, unless that member variable is marked mutable explicitly
- Can be passed to any other higher order function, a function that takes function as one of the input parameters, as they are not member functions
Lambdas can be recursive as ordinary functions are; however you need to name lambdas to make recursion work. Here is simple example of recursive lambda to calculate factorial:
Lambdas (Lambda Calculus) were first introduced by Alonzo Church as a formal system for function definition, application and recursion. It was proved that Lambda Calculus is Turing complete, there by making it theory of computation and then it made its way into functional languages.
C++ STL did introduce some functional concepts like higher order functions, std::find_if taking a predicate, but it has been of very limited form. With C++11 language support now for the first time function objects are truly first class concept in C++.
I have tried to cover most of the aspects of lambda expressions in C++11, but this is not all. I will post as and when I find something to share.
- Lambda Expressions and Closures (open-std.org)
- A proposal to add lambda functions to the C++ standard (open-std.org)
- Lambda expressions and closures for C++ (open-std.org)
- New wording for C++0x Lambdas (open-std.org)
- lambda functions proposal (comp.std.c++)
- Lambda parameters must have names (comp.std.c++)
- functional programming
- callable entity
- C++0x: Protected/private member access from lambda functions (comp.std.c++)
- lambda non-parameter variable binding (comp.std.c++)
- Lambda abstractions in C++ vs. Scheme (comp.lang.functional)
- lambda Functions??? (comp.lang.c++.moderated)
- Lambda expressions (i.e. anonymous functions) in C++ (comp.lang.c++.moderated)
- Templated Lambda Functions? (comp.lang.c++.moderated)