What is a lambda expression in C++11? When would I use one? What class of problem do they solve that wasn't possible prior to their introduction?
A few examples, and use cases would be useful.
What is a lambda expression in C++11? When would I use one? What class of problem do they solve that wasn't possible prior to their introduction?
A few examples, and use cases would be useful.
A lambda function is an anonymous function that you create in-line. It can capture variables as some have explained, (e.g. http://www.stroustrup.com/C++11FAQ.html#lambda) but there are some limitations. For example, if there's a callback interface like this,
you can write a function on the spot to use it like the one passed to apply below:
But you can't do this:
because of limitations in the C++11 standard. If you want to use captures, you have to rely on the library and
(or some other STL library like algorithm to get it indirectly) and then work with std::function instead of passing normal functions as parameters like this:
Answers
Q: What is a lambda expression in C++11?
A: Under the hood, it is the object of an autogenerated class with overloading operator() const. Such object is called closure and created by compiler. This 'closure' concept is near with the bind concept from C++11. But lambdas typically generate better code. And calls through closures allow full inlining.
Q: When would I use one?
A: To define "simple and small logic" and ask compiler perform generation from previous question. You give a compiler some expressions which you want to be inside operator(). All other stuff compiler will generate to you.
Q: What class of problem do they solve that wasn't possible prior to their introduction?
A: It is some kind of syntax sugar like operators overloading instead of functions for custom add, subrtact operations...But it save more lines of unneeded code to wrap 1-3 lines of real logic to some classes, and etc.! Some engineers think that if the number of lines is smaller then there is a less chance to make errors in it (I'm also think so)
Example of usage
Extras about lambdas, not covered by question. Ignore this section if you're not interest
1. Captured values. What you can to capture
1.1. You can reference to a variable with static storage duration in lambdas. They all are captured.
1.2. You can use lambda for capture values "by value". In such case captured vars will be copied to the function object (closure).
1.3. You can capture be reference. & -- in this context mean reference, not pointers.
1.4. It exists notation to capture all non-static vars by value, or by reference
1.5. It exists notation to capture all non-static vars by value, or by reference and specify smth. more. Examples: Capture all not-static vars by value, but by reference capture Param2
Capture all not-static vars by reference, but by value capture Param2
2. Return type deduction
2.1. Lambda return type can be deduced if lambda is one expression. Or you can explicitly specify it.
If lambda has more then one expression, then return type must be specified via trailing return type. Also, similar syntax can be applied to auto functions and member-functions
3. Captured values. What you can not capture
3.1. You can capture only local vars, not member variable of the object.
4. Сonversions
4.1 !! Lambda is not a function pointer and it is not an anonymous function, but capture-less lambdas can be implicitly converted to a function pointer.
p.s.
More about lambda grammar information can be found in Working draft for Programming Language C++ #337, 2012-01-16, 5.1.2. Lambda Expressions, p.88
In C++14 the extra feature which has named as "init capture" have been added. It allow to perform arbitarily declaration of closure data members:
One problem it solves: Code simpler than lambda for a call in constructor that uses an output parameter function for initializing a const member
You can initialize a const member of your class, with a call to a function that sets its value by giving back its output as an output parameter.
Well, one practical use I've found out is reducing boiler plate code. For example:
Without lambda, you may need to do something for different
bsize
cases. Of course you could create a function but what if you want to limit the usage within the scope of the soul user function? the nature of lambda fulfills this requirement and I use it for that case.The problem
C++ includes useful generic functions like
std::for_each
andstd::transform
, which can be very handy. Unfortunately they can also be quite cumbersome to use, particularly if the functor you would like to apply is unique to the particular function.If you only use
f
once and in that specific place it seems overkill to be writing a whole class just to do something trivial and one off.In C++03 you might be tempted to write something like the following, to keep the functor local:
however this is not allowed,
f
cannot be passed to a template function in C++03.The new solution
C++11 introduces lambdas allow you to write an inline, anonymous functor to replace the
struct f
. For small simple examples this can be cleaner to read (it keeps everything in one place) and potentially simpler to maintain, for example in the simplest form:Lambda functions are just syntactic sugar for anonymous functors.
Return types
In simple cases the return type of the lambda is deduced for you, e.g.:
however when you start to write more complex lambdas you will quickly encounter cases where the return type cannot be deduced by the compiler, e.g.:
To resolve this you are allowed to explicitly specify a return type for a lambda function, using
-> T
:"Capturing" variables
So far we've not used anything other than what was passed to the lambda within it, but we can also use other variables, within the lambda. If you want to access other variables you can use the capture clause (the
[]
of the expression), which has so far been unused in these examples, e.g.:You can capture by both reference and value, which you can specify using
&
and=
respectively:[&epsilon]
capture by reference[&]
captures all variables used in the lambda by reference[=]
captures all variables used in the lambda by value[&, epsilon]
captures variables like with [&], but epsilon by value[=, &epsilon]
captures variables like with [=], but epsilon by referenceThe generated
operator()
isconst
by default, with the implication that captures will beconst
when you access them by default. This has the effect that each call with the same input would produce the same result, however you can mark the lambda asmutable
to request that theoperator()
that is produced is notconst
.What is a lambda function?
The C++ concept of a lambda function originates in the lambda calculus and functional programming. A lambda is an unnamed function that is useful (in actual programming, not theory) for short snippets of code that are impossible to reuse and are not worth naming.
In C++ a lambda function is defined like this
or in all its glory
[]
is the capture list,()
the argument list and{}
the function body.The capture list
The capture list defines what from the outside of the lambda should be available inside the function body and how. It can be either:
You can mix any of the above in a comma separated list
[x, &y]
.The argument list
The argument list is the same as in any other C++ function.
The function body
The code that will be executed when the lambda is actually called.
Return type deduction
If a lambda has only one return statement, the return type can be omitted and has the implicit type of
decltype(return_statement)
.Mutable
If a lambda is marked mutable (e.g.
[]() mutable { }
) it is allowed to mutate the values that have been captured by value.Use cases
The library defined by the ISO standard benefits heavily from lambdas and raises the usability several bars as now users don't have to clutter their code with small functors in some accessible scope.
C++14
In C++14 lambdas have been extended by various proposals.
Initialized Lambda Captures
An element of the capture list can now be initialized with
=
. This allows renaming of variables and to capture by moving. An example taken from the standard:and one taken from Wikipedia showing how to capture with
std::move
:Generic Lambdas
Lambdas can now be generic (
auto
would be equivalent toT
here ifT
were a type template argument somewhere in the surrounding scope):Improved Return Type Deduction
C++14 allows deduced return types for every function and does not restrict it to functions of the form
return expression;
. This is also extended to lambdas.