capture by value class members

24,510

Solution 1

No, data members cannot be captured by value. A lambda can capture only two kinds of things:

  1. the this pointer, and
  2. 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();
    }
}
Share:
24,510
Lorenzo Pistone
Author by

Lorenzo Pistone

student of physics with the hobby of computer programming.

Updated on February 04, 2020

Comments

  • Lorenzo Pistone
    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
    Lorenzo Pistone over 11 years
    not 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
    Mooing Duck over 11 years
    Wait really? With [=] () { m = 1; } the this is captured by value? I would have expected the m to be captured by value. Then this oddity wouldn't have occured.
  • James McNellis
    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
    Mooing Duck over 11 years
    Well that's just silly. I can't imagine why they thought that was a good idea.
  • James McNellis
    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
    Mooing Duck over 11 years
    Given 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
    James McNellis over 11 years
    @MooingDuck: That doesn't just appear inconsistent. It is inconsistent, by the definition of "inconsistent." :-)
  • Dietmar Kühl
    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
    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
    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 write this->. That said, we discussed member captures for lambda on Monday and there is no good solution, as far as I can tell.
  • James McNellis
    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
    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
    John Dibling over 11 years
    While 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
    Ben Voigt over 10 years
    The 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
    Mohammad Alaggan about 7 years
    It appears that it is possible to capture "this" by value in C++17 : github.com/AnthonyCalandra/…
  • 463035818_is_not_a_number
    463035818_is_not_a_number about 5 years
    your 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 of BigObject you cannot capture a single member, no matter how cheap it might be to copy that single member
  • Flo Win
    Flo Win almost 5 years
    Capture intializers are a C+14 feature, question is tagged as C++11.