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 
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 
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 
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 
- 
     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. [...]()