Access C++14 lambda captures like struct members

2019-04-21 13:50发布

AFAIK, C++11/14 does not allow in-place definition of a new return type while defining a lambda. However, it seems a C++14 lambda capture expression essentially creates an anonymous type with one or more "members" and an operator (). So, why is that the compiler does not allow access to the captured members from outside the lambda. My feeble mind cannot handle the complexities of C++ but does it sound like a reasonable language extension to you? Here is an example.

vector<string> words = { "Stack", "Overflow" };
auto l = [w = words](){}; // almost like a C# anonymous type
cout << l.w[0]; // does not work. 

2条回答
可以哭但决不认输i
2楼-- · 2019-04-21 14:18

The status quo

This was discussed when lambda init-captures were added to the language. The current working draft of the standard (N3797) says (in [expr.prim.lambda]p11):

For every init-capture a non-static data member named by the identifier of the init-capture is declared in the closure type.

The standard does not specify the access of that member, making it unclear whether this is valid:

auto x = [n(0)] {};
int k = x.n; // ok?

This and some other specification problems with init-captures led to national body comment GB3 on the standard draft, which is handled by the C++ core working group as core issue 1760. In discussion of that issue, the core working group decided that the lambda's init-captures should not be accessible members of the closure object.

The resolution for issue 1760 (which is approved by CWG but not yet by the full committee) changes the specification to instead say:

An init-capture behaves as if it declares and explicitly captures a variable of the form “auto init-capture ;” whose declarative region is the lambda-expression's compound-statement [...]

This new wording makes it clear that the init-capture does not add a nameable member of the closure object, and it instead acts like any other lambda capture.

As a language extension

Making init-captures be accessible members of the closure type is certainly possible (and my initial implementation of init-captures in clang did that, before I implemented the resolution of issue 1760). It also seems like a useful feature, but it would also allow violation of the encapsulation of lambda-expressions in the common case where the init-captures should not be visible.

查看更多
Animai°情兽
3楼-- · 2019-04-21 14:40

If I'm understanding this right, you want to be able to access a variable that is captured within a lambda. But according to the top answer on Get captured variables from lambda?, it's not possible.

It's not possible by design

5.1.2 [expr.prim.lambda]

15 [...] For each entity captured by copy, an unnamed non-static data member is declared in the closure type. The declaration order of these members is unspecified. [...]

16 [...] It is unspecified whether additional unnamed non-static data members are declared in the closure type for entities captured by reference.

Captured variables are unnamed (or at least have names that are unspeakable by mortals) and their declaration order is deliberately unspecified. By-reference captures may not even exist in the closure type.

Bold emphasis mine.

查看更多
登录 后发表回答