I have this piece of code:
void function1(char c, bool b){
auto get_allowed = [&](int x){
if(b){
.... some code...
}
...some code...
}
get_allowed(0);
...other_code...
}
Can I use b inside the lambda function in this case??
I means, is the same thing to add that parameter into signature of lambda function, something like:
void function1(char c, bool b){
auto get_allowed = [&](int x,bool b){
if(b){
.... some code...
}
...some code...
}
get_allowed(0, false);
...other_code...
}
To clearify, the difference is here:
auto get_allowed = [&](int x){
get_allowed(0);
VS
auto get_allowed = [&](int x,bool b){
get_allowed(0, false);
where b is a parameter of the function function1.
In your example, the effect of both version of you lambda is roughly the same. However, there is a significant difference that lies in captured parameters vs "normal" parameters.
Here is how a lambda is created:
[ capture-list ] ( params ) { body }
The capture-list can give you access to variables that exist in the scope surrounding your lambda. There are some of the different capture modes:
[&] captures by reference all local variables in the surrounding scope (ie. b and c in your example)
[&b] captures only b by reference, you can put as many named variables as you wish (comma separated)
[=] captures by value all local variables in the surrounding scope (in other words: your lambda holds a copy of those variables)
[b] captures only b by copy
[b, &c] you can mix copy and reference captures
You should ask yourself : what are those captures for?
Well, it defines a closure, a context, which is the same each time the lambda is used. That kind of state added on top of a function is very useful in many situations.
One example: you are mapping a lambda on each element of a collection:
std::vector<int> numbers = {1, 2, 3, 4, 5};
int sum = 0;
std::for_each(std::begin(numbers), std::end(numbers),
[&sum](int n){ sum += n; });
Here, we are using a variable captured by reference to store (and update) the sum of all the numbers in the vector.
Take some time to reflect on this example, make some experiments of your own, and this is about all there is to know about lambdas. :)
The [&] capture list makes sure that the variables in the scope surrounding the definition of the lambda can be used by reference in the body of the lambda function.
So yes: in the first snippet, b is usable in the lambda (just don't forget the semi-column to end the function assignment). And you even can change its value (affecting b in get_allowed() would change the value of the parameter b of function1() as it is captured by reference) !
In the second snippet, you pass b as parameter by value. This works differently. There b is the name of a parameter passed by value, and it has nothing to do with the b of the enclosing scope.
Additional remarks
Attention: if your lambda survives the scope that defines it (for example, if you'd return the lambda from function1() or store the value of get_allowed), you could have problems with a capture by reference ; invoking the lambda later in another context could reference variables which no longer exist (dangling reference).
If you prefer a looser coupling, you may consider the [=] capture list instead: it has a similar effect, but the captured variables are passed by value (i.e. no accidental modification nor dangling references). This makes the lambda more independent the context in which it was created.
In the first example get_allowed is a function of one argument where b is captured implicitly (because you captured with [&]).
In the second, get_allowed is a function of two arguments where b is passed explicitly to get_allowed rather than taken from the surrounding function.
The lambda is unnecessary in this example so the difference is a bit academic.
Can I use b inside the lambda function in this case??
Yes, you can use b inside the lambda.
[&] captures all automatic variables odr-used in the body of the lambda by reference
b is captured by reference
Related
if I have defined in c++:
using CustomFunc = std::function<void(std::string input)>;
Now I a given lambda that captures CustomFunc by right value, and that lambda contains an inner lambda that calls the CustomFunc passed in from outer lambda:
//....
functionBThatTakesInALambda([](CustomFunc&& func){
std::string input = GeneratesRandomString();
myObj->functionBThatTakesInALambda([func](input){ func(input); });
});
//....
Assuming the first CustomFunc&& func is intentional and cannot be changed, should the send func in the inner function be capture by value as is, or &func instead ? (ie, can you capture by reference on an rvalue?)
Is there a better way to do the above? (assuming the outer and inner lambda structure must be preserved).
#include <iostream>
#include <functional>
int main(){
int a = 10;
std::function<int(int)> functionPointer = [a](int a)-> int{ return a + a + 100 ; };
int returnValue = functionPointer(50);
std::cout<<returnValue<<endl;
}
I was expecting 10+50+100 = 160 but the output is 10+10+100 = 120. Are there any changes I can make to get 160, whilst keeping the variable names as they are?
Actually there is a way to solve this problem without changing the variable or parameter name, by aliasing the capture:
std::function<int(int)> functionPointer = [b=a](int a)-> int{ return a + b + 100 ; };
As explained here, since C++14 lambda capture is generalized, which includes renaming variables of the lambda object. While a capture [a] would copy local variable a from outer scope into a lambda object variable a, we can also name that lambda object variable with the syntax [b=a], so the lambda's copy is known as b. We can also define lambda object variables with expressions, e.g. [a=5*a] or [b=5*a], which is sometimes a neat way of e.g. passing members of a struct or results of accessor methods to a lambda.
It allows to do things previously not possible, namely passing a unique_ptr to the lambda object (i.e. transferring ownership!) with std::move().
I believe there is no way to do exactly what you would like to as the compiler cannot have one variable a with two different values.
How are captures different than passing parameters into a lambda expression? When would I use a capture as opposed to just passing some variables?
for reference: http://en.cppreference.com/w/cpp/language/lambda#Lambda_capture
The reference only defines it as a "list of comma separated values" but not what they're for or why I'd use them.
To add: This is not the same question as "what is a lambda expression" because I'm not asking what a lambda expression is or when to use it. I'm asking what the purpose of a capture is. A capture is a component of a lambda expression, and can take values, but it's not well explained elsewhere on the internet what these values' intended purpose is, and how that is different from the passed values that follow the capture.
A capture is a binding to a free variable in the lambda form. They turn the lambda expression into a closed form (a closure), with no free variables. Consider:
auto f1 = [](int a, int x, int y){ return a * x + y; };
int x = 40, y = 2;
auto f2 = [x, y](int a){ return a * x + y; };
Despite bodies being the same, in the second form x and y are free variables (they are not bound among function's arguments) and thus need to be bound to existing objects (i.e. captured) at the moment of form's instantiation. In the first form they are function arguments, as you first suggested, and thus need not to be bound to existing objects at the moment of form instantiation. The difference is obvious: f1 is the function of three arguments, while f2 only accepts one.
What is more important, captures hold the part of lambda's local context that can outlive the context itself. A simple example:
auto f(int x) {
return [x](int a){ return a + x; };
}
Note that this function returns a fresh callable object, whose operator() accepts a single int and returns an int, and internally uses some value, a value of a variable that was local to the function f() and thus is no more accessible after the control has exited the function.
You may want to pass your lambda to a function that calls it with a specific number of arguments (e.g., std::find_if passes a single argument to your function). Capturing variables permits you to effectively have more inputs (or outputs, if you capture by reference).
Today I encountered a very unintuitive behavior (for me, at least) in C++11 lambdas. The code in question is the following:
#include <stdio.h>
auto sum(int x) {
return [&x](int y) {
return x + y;
};
}
int main() {
int a = sum(2)(3);
printf("%d\n",a);
}
Instead of printing 5, this prints gibberish. Actually, at least in my version of GCC, if I turn on the -O2 optimization flag, it actually prints 5. Since the output depends on the optimization level of the compiler, it is undefined behavior. After a while, I think I understood what is happening.
When the function sum is called, a stack variable corresponding to the argument x is set to 2, then the function sum returns, and this stack variable might be overwritten by anything that the compiler needs to put there to execute following code, and by the time the lambda eventually gets executed, the place where x was no longer holds 2, and the program adds 3 to an arbitrary integer.
Is there any elegant way to do currying in C++ guaranteeing that the variable gets captured correctly?
int x has a limited lifetime. References to automatic storage variables (what you call "the stack") are only valid over the variable's lifetime. In this case, only until the end of the stack frame (the scope) where the variable exists, or the function for function arguments.
[&] captures any mentioned ("local") variable by reference, except this (which is captured by value if used or implicitly used). [=] captures any mentioned variable by value. [x] would capture x explicitly, and [&x] by reference explicitly. In C++17, [*this] also works.
There is also [x=std::move(x)], or [blah=expression].
In general, if the lambda will outlive the current scope don't use [&]: be explicit about what you capture.
I know that capture lists make variables available inside a lambda function body like so:
int pos(0);
std::function<void()> incPos = [&pos](){ ++pos; };
incPos(); //pos is now 1
But how does that capturing actually work on compiler level? Where are the captured addresses or captured values stored?
Each lambda expression generates a unique function object (closure) that stores the captured variables as data members. For instance, the lambda expression in your code would be transformed into something like this by the compiler:
struct __uniquely_named_lambda
{
__uniquely_named_lambda(int& pos)
: pos(pos) {}
int& pos;
void operator()() const
{ ++pos; }
};
Invoking the lambda is simply a call to operator().
The data member is a reference since you captured by reference. If you captured by value it would be a plain int. Also note that generated operator() is const by default. This is why you cannot modify captured variables unless you use the mutable keyword.