12

In one of the recent C++0x drafts (n3225.pdf) we can find 5.1.2/10:

The identifiers in a capture-list are looked up using the usual rules for unqualified name lookup (3.4.1); each such lookup shall find a variable with automatic storage duration declared in the reaching scope of the local lambda expression. An entity (i.e. a variable or this) is said to be explicitly captured if it appears in the lambda-expression’s capture-list.

That seems rather restrictive to me. For example, it seems to me that the following things are disallowed:

int global;

struct s {
    int x;
    void memfun() {
        [x,global]{};
    }
};

since x is not necessarily a variable with automatic storage and neither is global. Note that the intention of this capture clause is to let the lambda object store a copy of x and global which might be desirable in case they are changed at a later stage. I am already aware of an alternative:

int global;

struct s {
    int x;
    void memfun() {
        int copyx = x;
        int copyglobal = global;
        [copyx,copyglobal]{};
    }
};

But this boils down to extra copies and additional boiler plate just to capture x and global as copy.

Also, i cannot find anything conclusive in the latest drafts about what happens if we name a local reference in the capture clause:

int main() {
    int  i = 0;
    int &r = i;
    assert([r]{return &r;}() != &i);
}

Does the lambda object "copy a reference" or "copy an int"? If it captures the referred object by copy, this can save us the additional copies from the previous work-around.

GCC apparently supports all these examples and stores a copy of an int in the last case (which is desirable, IMHO). But I would like to know whether this is in fact the intended behaviour according to the C++0x drafts or just a compiler-extension respectivly an implementatin bug.

Edit:

templatetypedef pointed out 5.1.2/14 which explains what happens when a reference is named in a capture-clause. As far as I can tell, this allows us to use the following work-around for the first example:

int global;

struct s {
    int x;
    void memfun() {
        auto& cx = x;
        auto& cglob = global;
        [cx,cglob]{};
    }
};

Tia, sellibitze

sellibitze
  • 27,611
  • 3
  • 75
  • 95

1 Answers1

11

From what you've posted it seems like your first example is illegal since neither captured variable has automatic duration. However, you can easily fix this. To capture the data member, you can just capture this, and the global doesn't need to be captured as you can just reference it directly.

EDIT: As you pointed out, this will not create a local copy of the value you want to capture. To capture these variables while making a copy, you can capture this, then explicitly create a local copy of the data member inside of the lambda.

As for the second question about capturing references, §5.1.2/14 says that capturing a variable of reference type by copy will create a copy of the value referenced instead of creating a copy of the reference. Thus the lambda will have its own copy of the value that the reference was referencing when it was created.

sellibitze
  • 27,611
  • 3
  • 75
  • 95
templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • 1
    The point of naming `x` and `global` in the capture clause was to let the lambda object store a *copy*. This might be desirable in case `::global` and `s::x` change their values. So, no, capturing `this` does not lead to the intended behaviour. – sellibitze Mar 29 '11 at 09:17
  • You are correct; I just updated my answer. Thanks for pointing that out! – templatetypedef Mar 29 '11 at 09:27
  • 2
    Thanks for pointing out 5.1.2/14. Looks like we can introduce local references to non-auto variables as a work-around if we are interested in capturing other things by copy. – sellibitze Mar 29 '11 at 09:38
  • 1
    Making a copy inside the lambda is still different from making a copy at the time of lambda creation. Not that it's difficult to do so, just can't use your proposal "solution". – Ben Voigt Mar 29 '11 at 13:33