Suppose copying a variable has a needed side effect. And I want to declare a lambda that copies the variable but doesn't otherwise use the variable. What's the minimum required to do this?
Copiable copyable;
auto lambda1 = [=](){};
auto lambda2 = [copyable](){};
auto lambda3 = [=](){ copyable; }
auto lambda4 = [=](){ volatile copy = copyable; }
lambda1
uses implicit capture, and since the body doesn't mention copyable
, I don't believe it actually copies it.
lambda2
uses explicit capture, and it seems according to this, it should capture by copy. Is the compiler allowed to elide the copy? See this for another discussion of this.
lambda3
uses implicit capture but the body mentions copyable
. Does this constitute an odr-use of copyable
?
lambda4
uses implicit capture and forces another volatile
copy. I'm sure this will actually work, but it's doing more copies than the minimum.
Motivating case: I need to run a cleanup after an arbitrary number of lambda calls are completed, possibly in different threads. I can do this by using a std::shared_ptr
with a custom deleter that runs the cleanup, and somehow passing this to each lambda. Then when all the shared ptrs go out of scope, the cleanup will run.
Edit: lambda3
and lambda4
were missing the =
for implicit capture.
Much like functions can change the value of arguments passed by reference, we can also capture variables by reference to allow our lambda to affect the value of the argument. To capture a variable by reference, we prepend an ampersand ( & ) to the variable name in the capture.
Lambdas can both capture variables and accept input parameters. A parameter list (lambda declarator in the Standard syntax) is optional and in most aspects resembles the parameter list for a function. auto y = [] (int first, int second) { return first + second; };
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.
It's a lambda capture list and has been defined in C++ from the C++11 standard. [&] It means that you're wanting to access every variable by reference currently in scope within the lambda function.
What's the minimum required to do this?
Explicit capture by value, as in lambda2
.
lambda1
uses implicit capture, and since the body doesn't mention copyable, I don't believe it actually copies it.
That's right. Variables are only implicitly captured if they're odr-used within the lambda.
lambda2
uses explicit capture, and it seems according to this, it should capture by copy.
That's right. Any explicitly captured variables will be captured, whether they're used or not. This is what you want to do to ensure your object is captured.
Is the compiler allowed to elide the copy? See this for another discussion of this.
No. If a variable is captured, then it's captured. The link doesn't really "discuss" that; the only answer confirms that this is the case, with the appropriate wording from the standard.
lambda3
uses implicit capture but the body mentions copyable. Does this constitute an odr-use of copyable?
Yes. The definition of odr-use is
A variable whose name appears as a potentially-evaluated expression is odr-used unless it is an object that satisfies the requirements for appearing in a constant expression and the lvalue-to-rvalue conversion is immediately applied.
and the exception doesn't apply since it isn't constant (and therefore can't appear in a constant expression). (But note that this is ill-formed since there's no default capture.)
lambda4
uses implicit capture and forces another volatile copy. I'm sure this will actually work, but it's doing more copies than the minimum.
Indeed; you're forcing implicit capture by using the value, and forcing an extra copy. That's unnecessary, since lambda2
does what you want.
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