There once was a long disscusion going on whether closure types should be considered as structural types or not (essentially determining whether they would be eligible as NTTPs). An elaborated post about this, made by user dfrib, can be found here.
The initial concern about this seemed to be raised by Zhihao Yuan, back in March 2022. This ended up becoming defect report CWG 2542, which was accepted by a working group meeting in June 2023. The proposed resolution of that defect report was approved and it very clearly stated that closure types are not structural types.
This change was reflected in many versions of the C++ Working Draft, at least all the way up to N4971. The passage of interest being listed under [expr.prim.lambda.closure]/3
. This is also what people will find when looking up the cppreference entry about lambdas, which references defect report CWG 2542 at the bottom of the page.
However, in the more recent C++ Working Draft version N4981, passage [expr.prim.lambda.closure]/3 now reads:
The closure type is not an aggregate type (9.4.2); it is a structural type (13.2) if and only if the lambda has no lambda-capture.
Which seems to revert the approved resolution of defect report CWG 2542. Should this defect report now be considered obsolete? And, by which meeting/decision/paper did closure types now become structural types?
The history here was pretty odd.
CWG 2542 was an issue submitted by Zhihao Yuan wondering about the validity of this example:
template <auto V>
void foo() {}
void bar() {
foo<[i = 3] { return i; }>();
}
Since the rules for structural types require all public members and the data members of a lambda are unnamed and unspecified - so it's not clear if they're public or not.
Core decided to resolve this issue by going all out and rejecting all lambdas from consideration from being structural - regardless of whether they have capture or not.
So then I submitted CWG 2845 building on top of Zhihao's example, pointing out that:
template <auto V>
void foo() {}
void bar() {
foo<[i = 3] { return i; }>(); // #1: error
foo<[]{}>(); // #2: error
foo<+[]{}>(); // #3: OK, a function pointer is a structural type
}
Which was then resolved to consider lambdas with no capture as being structural.
This latter issue was adopted in the Tokyo meeting in March 2024 (which is where the current wording quoted in OP comes from), which you can think of as reverting/fixing the incorrect resolution of the former issue.
And, by which meeting/decision/paper did closure types now become structural types?
This was CWG2845 whose proposed and accepted resolution was to make a captureless lambda a structural type.
This can be seen from CWG2845:
Make the closure type of a captureless lambda a structural type
Issue 2542 (approved in June, 2023) made all closure types not be structural types, i.e. unsuitable for use as non-type template parameters. This causes an inconsistency with the treatment of the pointer-to-function conversion for closure types with no captures:
Proposed resolution (approved by CWG 2024-02-02):
Change in 7.5.5.2 [expr.prim.lambda.closure] paragraph 3 as follows:
- The closure type is not an aggregate type (9.4.2 [dcl.init.aggr]) and not ; it is a structural type (13.2 [temp.param]) if and only if the lambda has no lambda-capture. An implementation may define the closure type differently from ...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With