I have a function in a class that defines a lambda and stores it in a local static variable:
class A { public: void call_print() { static auto const print_func = [this] { print(); }; print_func(); }; virtual void print() { std::cout << "A::print()\n"; } }; class B : public A { public: virtual void print() override { std::cout << "B::print()\n"; } };
I also execute the following test:
int main() { A a; B b; a.call_print(); b.call_print(); }
(Live Sample)
What I expect to be printed is:
A::print() B::print()
But what I really get is:
A::print() A::print()
(Same object address is also printed with each)
I suspect this is due to the this
capture. I assumed that it would capture the value of this
when it is called, however it seems to be captured the moment the lambda is defined.
Could someone explain the semantics of lambda captures? When do they actually get provided to the function? Is it the same for all capture types, or is this
a special case? Removing static
fixes the problem, however in my production code I'm actually storing the lambda in a slightly-heavier object which represents a slot to which I insert into a signal later.
The lambda is capturing an outside variable. A lambda is a syntax for creating a class. Capturing a variable means that variable is passed to the constructor for that class. A lambda can specify whether it's passed by reference or by value.
A capture clause of lambda definition is used to specify which variables are captured and whether they are captured by reference or by value. An empty capture closure [ ], indicates that no variables are used by lambda which means it can only access variables that are local to it.
Lambdas always capture objects, and they can do so by value or by reference.
The [=] you're referring to is part of the capture list for the lambda expression. This tells C++ that the code inside the lambda expression is initialized so that the lambda gets a copy of all the local variables it uses when it's created.
This has nothing to do with the semantics of lambda capture. It's simply how static
works.
A static
function-scoped variable is initialized exactly once. There is only ever one such object in your entire program. It will be initialized the first time the function is called (more specifically, the first time the static
statement is executed). And therefore, the expression used to initialize the static
variable is only ever invoked once.
So if a static
function-scoped variable is initialized with data that's based on one of the function's parameters (like this
), then it will only get the parameters from the first invocation of that function.
Your code creates a single lambda. It does not create different lambdas on each invocation of the function.
The behavior you seem to want is not a function-local static
variable, but an object member. So just put a std::function
object in the class itself, and have call_print
initialize it if it is empty.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With