On 10/01/2020 12:42 PM, John W. Eaton
wrote:
On
10/1/20 2:33 PM, Rik wrote:
"should work", but needs to be checked.
The first lambda _expression_ I wrote for Octave would not work
with capture which is why I used the parameter-passing approach.
Do you remember what it was that didn't work?
I don't. It might work now that we've switched to unwind_action
rather than unwind_protect objects.
Except for "this", lambdas capture by value by default. Capturing
"this" allows access to the current object, so instead of writing
unwind_action restore_scope
([] (auto self) { self->pop (); }, this);
we can write
unwind_action restore_scope ([this] (void) { pop (); });
and instead of
unwind_action executing_callbacks_cleanup
([] (auto old_callback_props, auto &self)
{ old_callback_props->erase (self); },
&executing_callbacks, this);
we can write
unwind_action executing_callbacks_cleanup
([this] () { executing_callbacks.erase (this); });
In this last case, "executing_callbacks" is also a file-scope
static variable, so the lambda can access it directly without
capture.
I like these as even simpler, less verbose forms.
We could also decide to always use "[=]" when we need to capture
something. Then all variables that are needed, including "this"
will be captured using the default rules for capture by value.
I don't think this is recommended practice. The temporary anonymous
struct that is created to represent the lambda _expression_ will then
have an argument in the constructor for every existing variable in
the surrounding function. The compiler *might* then optimize out
all of the additional unused captures, but I think it would be
better to just capture what you need either by value
"[=variable_name]" if small like a built-in type or a pointer or by
reference "[&variable_name]" if it is something large like the
instance of a class. For reference, I was using this
https://dzone.com/articles/all-about-lambda-functions-in-cfrom-c11-to-c17.
The unwind_action + lambda _expression_ feature is definitely
complicated and has a lot of options for how to use it. There's
no one right way. I'd just like to agree on a set of guidelines to
make it as simple as possible to write, understand, and maintain.
My first pass at that would be
* when possible, capture variables by value directly in the
lambda _expression_ instead of the unwind_action object
I would modify this to only small values should be passed by value.
* use lambda _expression_ arguments and capture values in the
unwind_action object only when necessary (for example, when the
value is not a variable in the local scope)
This seems like a good convention to adopt.
and possibly
* use "[=]" to capture local variables and avoid the redundancy
of explicitly writing the list of captured variables since they
will already appear in the lambda _expression_ anyway
I would skip this as noted above.
--Rik
and, once we can move to C++14, maybe also add
* use "auto" for lambda _expression_ argument declarations
jwe
|