What Is a Lambda Expression in C++11

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



Leave a reply



Submit