capture by value class members
Solution 1
No, data members cannot be captured by value. A lambda can capture only two kinds of things:
- the
this
pointer, and - nonstatic local variables (that is, variables with automatic storage duration).
As has been noted by ildjarn in the comments, you can create a local variable with a copy of the value of the data member, and capture that local variable by value.
I would argue that if explicit by-value capture of a data member was allowed, it could prove confusing, since the behavior of explicit capture would differ from that of implicit capture. For example, given an accessible data member of type int
named m
, it would be odd that the following would produce different results:
[=] () mutable { m = 1; } // we modify this->m
[=m]() mutable { m = 1; } // we modify the copy of m that was captured
Solution 2
Yes, simply write the [<new name>=<your class field>]
construct.
For instance:
class MyClass {
int a;
void foo() {
auto my_lambda = [a_by_val=a] {
// do something with a_by_val
}
my_lambda();
}
}
Lorenzo Pistone
student of physics with the hobby of computer programming.
Updated on February 04, 2020Comments
-
Lorenzo Pistone over 4 years
Is there a way, when writing a lambda function within a member function, to capture fields of the enclosing class by value? The default catch-all
=
doesn't work because when I reference the variable inside the lambda I get instead a dereferencing from the captured this pointer, as well as explicitly naming the variable in the capture list, because I get two compile error:capture of non-variable <name>
, and‘this’ was not captured for this lambda function
-
Lorenzo Pistone over 11 yearsnot really. I don't want to capture all of them. I just want to capture one, by value, with whatever syntax in the capture list.
-
Mooing Duck over 11 yearsWait really? With
[=] () { m = 1; }
thethis
is captured by value? I would have expected them
to be captured by value. Then this oddity wouldn't have occured. -
James McNellis over 11 years@MooingDuck: Yes. If you use any nonstatic member in a lambda, the
this
pointer is captured by value. -
Mooing Duck over 11 yearsWell that's just silly. I can't imagine why they thought that was a good idea.
-
James McNellis over 11 years@MooingDuck: Consistency. Let's say we call a nonstatic member function from the body of the first lambda:
f();
. Do you expect that member function to be called on*this
or on a copy of*this
? -
Mooing Duck over 11 yearsGiven a member function, I would expect the lambda to implicitly capture the
this
pointer by value for member functions, but member variables should be captured according to whatever is in the[]
. It might appear inconsistent, but that's definitely how I would expect it to behave. -
James McNellis over 11 years@MooingDuck: That doesn't just appear inconsistent. It is inconsistent, by the definition of "inconsistent." :-)
-
Dietmar Kühl over 11 years@JamesMcNellis: Actually your lambda doesn't work:
[=m]() mutable { m = 1; }
still doesn't allow you to capture a member! The only way to capture a member is to name it:auto mc = m; [mc]() mutable { mc= 1; }
-
Mooing Duck over 11 years@DietmarKühl: it compiles, but you're right that it doesn't quite work as I expected.
-
Dietmar Kühl over 11 years@MooingDuck: The lambda capture always captures variables from the local scope. Member variables are not in the locale scope so you can't touch them. Also, the member is really accessed as
this->m
except that you don't have to writethis->
. That said, we discussed member captures for lambda on Monday and there is no good solution, as far as I can tell. -
James McNellis over 11 years@DietmarKühl: Right. I was saying that if it was allowed, we'd end up with the inconsistency noted in the example. Apparently the implied "if" was not clear; my apologies to all who may have been confused. [Aside: I hope you all are having fun in Portland :-)]
-
Dietmar Kühl over 11 years@MooingDuck: If the code compiles, it is wrong! First off, to capture a variable by value you just name the variable. ... and members can't be captured - yet! ;)
-
John Dibling over 11 yearsWhile fast code can be written in C++, I think it is not quite accurate to classify the language being about speed. It is about much more than just speed.
-
Ben Voigt over 10 yearsThe C++14 arbitrary expression capture capability should solve this problem, by allowing capture by value and giving it a different name at the same time, thus avoiding the inconsistency.
-
Mohammad Alaggan about 7 yearsIt appears that it is possible to capture "this" by value in C++17 : github.com/AnthonyCalandra/…
-
463035818_is_not_a_number about 5 yearsyour argument is moot, lets say I have
BigObject foo;
then it is perfectly fine to capture the whole object by value, but inside a method ofBigObject
you cannot capture a single member, no matter how cheap it might be to copy that single member -
Flo Win almost 5 yearsCapture intializers are a C+14 feature, question is tagged as C++11.