What is a lambda expression in C++11?
The problem
C++ includes useful generic functions like std::for_each
and std::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.
#include <algorithm>
#include <vector>
namespace {
struct f {
void operator()(int) {
// do something
}
};
}
void func(std::vector<int>& v) {
f f;
std::for_each(v.begin(), v.end(), f);
}
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:
void func2(std::vector<int>& v) {
struct {
void operator()(int) {
// do something
}
} f;
std::for_each(v.begin(), v.end(), f);
}
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:
void func3(std::vector<int>& v) {
std::for_each(v.begin(), v.end(), [](int) { /* do something here*/ });
}
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.:
void func4(std::vector<double>& v) {
std::transform(v.begin(), v.end(), v.begin(),
[](double d) { return d < 0.00001 ? 0 : d; }
);
}
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.:
void func4(std::vector<double>& v) {
std::transform(v.begin(), v.end(), v.begin(),
[](double d) {
if (d < 0.0001) {
return 0;
} else {
return d;
}
});
}
To resolve this you are allowed to explicitly specify a return type for a lambda function, using -> T
:
void func4(std::vector<double>& v) {
std::transform(v.begin(), v.end(), v.begin(),
[](double d) -> double {
if (d < 0.0001) {
return 0;
} else {
return d;
}
});
}
"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.:
void func5(std::vector<double>& v, const double& epsilon) {
std::transform(v.begin(), v.end(), v.begin(),
[epsilon](double d) -> double {
if (d < epsilon) {
return 0;
} else {
return d;
}
});
}
You can capture by both reference and value, which you can specify using &
and =
respectively:
[&epsilon, zeta]
captures epsilon by reference and zeta by value[&]
captures all variables used in the lambda by reference[=]
captures all variables used in the lambda by value[&, epsilon]
captures all variables used in the lambda by reference but captures epsilon by value[=, &epsilon]
captures all variables used in the lambda by value but captures epsilon by reference
The generated operator()
is const
by default, with the implication that captures will be const
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 as mutable
to request that the operator()
that is produced is not const
.
c++11 what is the scope for the lambda function below
A lambda expression returns an instance of an anonymously-defined class (the type is known only to the compiler). This class overloads the operator ()
to serve as a function object.
On top of that, lambda expressions that don't close over any state have the added specification that they can be implicitly converted to a C-style function pointer. In those cases, imagine that the operator ()
just invokes a static function (and the implicit conversion is a pointer to that static function).
Knowing all of this, we can say the following things about the code you posted:
- Every time the
fx
function is invoked, an instance of the anonymous class is created- This instance is an r-value; as such it only exists until the end of the statement
- The function pointer returned by the
fx
function is effectively a pointer to a static function - The function pointer can be safely used by whoever has possession of it (because it is a static function with no shared state)
C++11 lambda expression - Capture vs Argument Passing
Why the first one always returns true?
Lambdas decay into function pointers, which are implicitly convertible to booleans (always true
for lambdas because the pointer is never null).
Why second fails to compile?
Lambdas that capture anything do not have this conversion to a function pointer (how would that state get through?)
If you must use a lambda:
Call it:
return [](int n1, int n2) { return n1 > n2; }(n1, n2); //notice the () to call it
Or, your second way, which makes more sense, but not as much as just return n1 > n2
:
return [=] { return n1 > n2; }(); //= captures everything used by value
//-> bool and parameter list are redundant
Finally, it's worth noting that std::greater
, in <functional>
, already does this:
std::sort(…, std::greater<int>()); //std::greater<> in C++14
In C++11, is lambda function same with lambda expression and closure?
What is a closure (quoting from wikipedia):
In programming languages, closures (also lexical closures or function
closures) are a technique for implementing lexically scoped name
binding in languages with first-class functions. Operationally, a
closure is a record storing a function[a] together with an
environment: a mapping associating each free variable of
the function (variables that are used locally, but defined in an
enclosing scope) with the value or storage location to which the name
was bound when the closure was created[b]. A closure,
unlike a plain function, allows the function to access those captured
variables through the closure's reference to them, even when the
function is invoked outside their scope.[a] The function may be stored as a reference to a function,
such as a function pointer.[b] These names most frequently refer to values, mutable
variables, or functions, but can also be other entities such as
constants, types, classes, or labels.
What is a lambda expression (quoting from wikipedia):
In computer programming, an anonymous function (function literal,
lambda abstraction) is a function definition that is not bound to an
identifier.Since C++11, C++ supports anonymous functions, called lambda
expressions, which have the form:[capture](parameters) -> return_type { function_body }
An example lambda function is defined as follows:
[](int x, int y) -> int { return x + y; }
Since C++11, C++ also supports closures. Closures are defined between
square brackets [and] in the declaration of lambda expression. The
mechanism allows these variables to be captured by value or by
reference. The following table demonstrates this:[] //no variables defined. Attempting to use any external variables in the lambda is an error.
[x, &y] //x is captured by value, y is captured by reference
[&] //any external variable is implicitly captured by reference if used
[=] //any external variable is implicitly captured by value if used
[&, x] //x is explicitly captured by value. Other variables will be captured by reference
[=, &z] //z is explicitly captured by reference. Other variables will be captured by value
Résumé
Terms Lambda expression and Lambda function are used interchangeably for signifying the definition/declaration of an anonymous function object as:
[capture](parameters) -> return_type { function_body }
With the term closure we refer to the run-time function object created by the evaluation of a lambda expression.
Now for lambdas to be evaluated at compile time, this would require a lambda to be a constant expression. Unfortunately, lambdas aren't constexpr
and as such can't be evaluated at compile time. However, there's a proposal submitted to the committee N4487 that suggests that with the lifting of some restrictions we could have constexpr
lambdas. That is, in the future we might have constexpr
lambdas that could be evaluated at compile time.
What is the motivation behind C++11 lambda expressions?
I don't think it's nearly as much about the computational performance as increasing the expressive power of the language.
I need to rewrite c++ 11 code in c++98, c++ 11 is using lambda function [&](const Output & o
Seems like a pointless use of lambda's anyway:
std::for_each(m_outputs.begin(), m_outputs.end(), &process);
That said, a lambda is just an object with an operator()
. You can always write the underlying type manually, and create an instance. Lambda's save lines of code, but are not magic.
[edit]
Since we've learned that the question is about captures, [&]
captures variables by reference. That means adding one or more reference variable to the replacement type you're writing.
C++11 lambda implementation and memory model
My current understanding is that a lambda with no captured closure is exactly like a C callback. However, when the environment is captured either by value or by reference, an anonymous object is created on the stack.
No; it is always a C++ object with an unknown type, created on the stack. A capture-less lambda can be converted into a function pointer (though whether it is suitable for C calling conventions is implementation dependent), but that doesn't mean it is a function pointer.
When a value-closure must be returned from a function, one wraps it in std::function. What happens to the closure memory in this case?
A lambda isn't anything special in C++11. It's an object like any other object. A lambda expression results in a temporary, which can be used to initialize a variable on the stack:
auto lamb = []() {return 5;};
lamb
is a stack object. It has a constructor and destructor. And it will follow all of the C++ rules for that. The type of lamb
will contain the values/references that are captured; they will be members of that object, just like any other object members of any other type.
You can give it to a std::function
:
auto func_lamb = std::function<int()>(lamb);
In this case, it will get a copy of the value of lamb
. If lamb
had captured anything by value, there would be two copies of those values; one in lamb
, and one in func_lamb
.
When the current scope ends, func_lamb
will be destroyed, followed by lamb
, as per the rules of cleaning up stack variables.
You could just as easily allocate one on the heap:
auto func_lamb_ptr = new std::function<int()>(lamb);
Exactly where the memory for the contents of a std::function
goes is implementation-dependent, but the type-erasure employed by std::function
generally requires at least one memory allocation. This is why std::function
's constructor can take an allocator.
Is it freed whenever the std::function is freed, i.e., is it reference-counted like a std::shared_ptr?
std::function
stores a copy of its contents. Like virtually every standard library C++ type, function
uses value semantics. Thus, it is copyable; when it is copied, the new function
object is completely separate. It is also moveable, so any internal allocations can be transferred appropriately without needing more allocating and copying.
Thus there is no need for reference counting.
Everything else you state is correct, assuming that "memory allocation" equates to "bad to use in real-time code".
Parameter list in Lambda
Lambda creation
I think I had the same confusion when I first saw lambdas.
So let's see what this expression means:
[](auto x, auto y) {return(y < x); }
This just creates the lambda object. It does not call the labda. Think of it as a class definition + object creation.
Your questions
Let's consider the declaration of sort
:
template< class RandomIt, class Compare >
void sort( RandomIt first, RandomIt last, Compare comp );
and your call to it
sort(ivec.begin(), ivec.end(), [](auto x, auto y) { return(y < x); });
when the above line of code is being executed?
I'll interpret this as "when is the body of the lambda executed?"
Whenever sort
calls it. What you need to understand: sort
receives a parameter named comp
that is callable. This parameter can be of type: pointer to function or a callable type (i.e. a type with operator()
defined). A lambda is a special case of a callable type. When you call sort
you just pass this object to the sort
function. Now sort
has an object (comp
) that it can call whenever it wants/needs.
what is being passed in the parameter list as parameter?
Whatever sort
passes as arguments when it calls comp
. It the case of std::sort
it will call it with pairs of elements from the range with the purpose of determining if those two elements are already sorted between them or not.
Example
The easiest is to just see it in action. For this lets consider the simplest sorting algorithm: a dumb bubble sort:
template< class RandomIt, class Compare >
void bubble_sort( RandomIt first, RandomIt last, Compare comp )
{
for (auto left = first; left != last; ++left)
{
for (auto right = std::next(left); right != last; ++right)
{
if (!comp(*left, *right))
{
std::swap(*left, *right);
}
}
}
}
the algorithm is for exposition only
As you can see bubble_sort
makes calls to comp
by passing arguments. Like std::sort
the arguments passed are pairs of elements from the [first, last)
range.
Related Topics
Find Middle Elements from an Array
How to Print Function Pointers With Cout
What Is a Reference Variable in C++
Stack, Static, and Heap in C++
Initialization of All Elements of an Array to One Default Value in C++
A Positive Lambda: '+[]{}' - What Sorcery Is This
Checking If a Double (Or Float) Is Nan in C++
How to Make My Custom Type to Work With "Range-Based For Loops"
Recursive Function That Returns All Substrings of a String
Sorting Output Numbers Without an Array
How to Determine the Boost Version on a System
Pass Parameter to Base Class Constructor While Creating Derived Class Object
Given an Integer N. What Is the Smallest Integer Greater Than N That Only Has 0 or 1 as Its Digits
How to Properly Clean Up Elements from Vectors of Object Pointers
Why Must a Short Be Converted to an Int Before Arithmetic Operations in C and C++