You attempt myInvoke
to accept the function fn
by reference, but the count
lambda that you pass is not a std::function
.
Each time you call myInvoke
with your lambda, it is converted to a std::function
by means of creating a temporary object (a copy). That's what fn
is referencing.
And so i
will be modified on the copy and will not affect your count
lambda.
This is also why accepting fn
by value behaves similarly.
One way to handle it is to make myInvoke
a function template where fn
is a template argument (of type T &
), so no conversion needs to be done.
Code example:
#include <iostream>
#include <functional>
template <typename T>
void myInvoke(T & fn)
{
fn();
}
int main()
{
int i{ 0 };
// Increments and prints its local copy of @i.
auto count = [i]() mutable {
std::cout << ++i << '\n';
};
myInvoke(count);
myInvoke(count);
myInvoke(count);
}
Output:
1
2
3
An alternative way would be to make count
of type std::function<void()>
as suggested in the other answer by @Matt.
This will also prevent the creation of temporary copies per call, since the fn
would be able to bind to it directly.
Note:
Another option that was mentioned is to change your lambda to capture i
by reference instead of by value:
//------------vv------------
auto count = [&i]() { ... };
This will output 1 2 3
as you expect, but only because all function copies will actually modify the i
on the stack of main
.
I thought this is not what you wanted, but rather to increment only the i
member of the lambda.
std::function
gets a copy of the lambda instance. – Egestauto count{ [&]() { std::cout << ++i << '\n'; } };
– Hockenberry1 2 3
output, it will be only via changing thei
inmain
, and I don't think this is what the OP tried to achieve. In the begining I was going in that direction as well, but then thought the OP would like to use thei
member of the lambda, without affectingi
ofmain
. My answer shows how to do it, as well as the answer by Matt. – Signposti
member of the lambda only (without affectingi
inmain
) ? – Signpost