1. Revision History
EWG discussed this change as [EWG135] in Lenexa and voted 15 to 1 on forwarding to core. It became [CWG2121], discussed in Kona and needed someone to volunteer wording. This paper presents text that implements that decision, for consideration.
[P1102R0] was published in June 2018. It was discussed on the EWG reflector in June 2018, Nina Ranns provided feedback, and EWG chair agreed that the paper should move to CWG directly given previous polls.
[P1102R1] responded to feedback about ambiguous requires-clauses from Hubert Tong and was discussed in a CWG teleconference on 2020-12-07.
P1102R2 incorporates the feedback given by CWG during that teleconference.
2. Introduction and motivation
Currently, C++ lambdas with no parameters do not require a parameter declaration clause. The specification even contains this language in [expr.prim.lambda] section 8.4.5 ❡4:
If a lambda-expression does not include a lambda-declarator, it is as if the lambda-declarator were
.
()
This allows us to omit the unused
in simple lambdas such as this:
std :: string s1 = "abc" ; auto withParen = [ s1 = std :: move ( s1 )] () { std :: cout << s1 << '\n' ; }; std :: string s2 = "abc" ; auto noSean = [ s2 = std :: move ( s2 )] { // Note no syntax error. std :: cout << s2 << '\n' ; };
These particular lambdas have ownership of the strings, so they ought to be able
to mutate it, but
and
are const (because the
operator is
declared
by default) so we need to add the
keyword:
std :: string s1 = "abc" ; auto withParen = [ s1 = std :: move ( s1 )] () mutable { s1 += "d" ; std :: cout << s1 << '\n' ; }; std :: string s2 = "abc" ; auto noSean = [ s2 = std :: move ( s2 )] mutable { // Currently a syntax error. s2 += "d" ; std :: cout << s2 << '\n' ; };
Confusingly, the current Standard requires the empty parens when using the
keyword. This rule is unintuitive, causes common syntax errors, and
clutters our code. When compiling with clang, we even get a syntax error that
indicates the compiler knows exactly what is going on:
example.cpp:11:54: error: lambda requires'()' before'mutable' autonoSean = [ s2 = std::move( s2)] mutable{ // Currently a syntax error. ^() 1 error generated.
This proposal would make these parentheses unnecessary like they were before we
added
. This will apply to:
-
lambda template parameters
-
constexpr -
mutable -
consteval -
Exception specifications and
noexcept -
attributes
-
trailing return types
-
requires
3. Impact
This change will not break existing code.
4. Wording
Modify Lambda expressions [expr.prim.lambda] as follows:
lambda-expression : lambda-introducer lambda-declarator optcompound-statementlambda-introducer < template-parameter-list > requires-clauseopt lambda-declarator optcompound-statementlambda-introducer : [ lambda-captureopt ] lambda-declarator: lambda-specifiers ( parameter-declaration-clause ) decl-specifier-seqoptlambda-specifiersnoexcept-specifieropt attribute-specifier-seqopt trailing-return-typeoptrequires-clauseoptlambda-specifiers: decl-specifier-seqoptnoexcept-specifieropt attribute-specifier-seqopt trailing-return-typeopt
The opt after lambda-declarator is removed because lambda-declarator can now be empty and the opt would be redundant. lambda-specifiers is given a name to reduce redunancy in the grammar.
Modify ❡4 to clarify that all lambda-expressions now have a lambda-declarator but it may be empty:
If a lambda-expressiondoes not include aincludes an empty lambda-declarator, it is as if the lambda-declarator were. [...]
()