Reputation: 8333
Is there any way to change the variable captured by copy in a lambda from the outside?
Example:
#include <iostream>
int main() {
int x = 3;
auto f = [x]() { std::cout << x << std::endl; };
// is there anything I can do here to make f print 4?
f();
}
If this is possible, it feels really dirty. Is there a compelling reason why I shouldn't even think about doing so?
Upvotes: 4
Views: 4664
Reputation: 275350
struct do_nothing{ template<class...Args> void operator()(Args&&...)const{}};
template<class...cmd>
struct maybe_run_t;
template<> struct maybe_run_t<>:do_nothing{};
template<class cmd>struct maybe_run_t<cmd>{
cmd&& value;
template<class...Args>
void operator()(Args&&...args)const{
value(std::forward<Args>(args)...);
}
};
template<class...Args>
maybe_run_t<Args...> maybe_run(Args&&...args){
return {std::forward<Args>(args)...};
}
Then:
int x = 3;
auto f = [x](auto&&...cmd)mutable { maybe_run(cmd...)(x); std::cout << x << std::endl; };
// is there anything I can do here to make f print 4?
f([](auto&x){x=4;});
f();
Prints 4\n4\n
.
You have an optional argument. If you pass one, it gets to modify x
. If you do not, the code works.
You could also do flow control based on its existence or return value.
Upvotes: 0
Reputation: 50540
In C++14, you can do this:
#include<iostream>
int main() {
int x = 0;
auto l = [x]()mutable->decltype(auto){
std::cout << x << std::endl;
return (x);
};
l() = 42;
l();
}
Actually, it's pretty easy to do something similar also in C++11:
auto l = [x]()mutable->decltype(x)&{
std::cout << x << std::endl;
return x;
};
That is, you can modify the variable captured by copy simply by returning it by reference.
Upvotes: 0
Reputation: 372
To answer your question, no it is not possible to change local variables of a function/functor (which is what lambda is) from the outside.
Think of lambda as "regular" functions whose name you don't have. Just like for regular functions you can't change local variable values from the outside (params passed by value), you can't do it with lambda too. This is a necessary requirement for security & predictability of the result.
If you have a problem where you need to do this, as others have suggested use [&]
syntax.
(There exists https://www.eecs.umich.edu/courses/eecs588.w14/static/stack_smashing.pdf but I think that relies on knowledge of compiler/system implementation and usually gets into undefined behaviour)
Upvotes: 1
Reputation: 1594
Revert back to the original 'lambda' type: create a struct or class with an operator()
struct myLambda
{
int x;
myLambda(int x) : x(x) {};
operator() { std::cout << x << '\n'; }
};
Upvotes: 0
Reputation: 1341
#include <iostream>
int main()
{
int x = 3;
auto f = [&x]() { std::cout << x << std::endl; };
x++;
f();
}
Upvotes: 4