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 responds to feedback about ambiguous requires-clauses from Hubert Tong.
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 -
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-parameter-listopt lambda-declaratoroptlambda-specifierscompound-statement lambda-introducer < template-parameter-list > requires-clauseopt lambda-parameter-list-and-specifiersopt lambda-declaratoroptcompound-statementlambda-introducer : [ lambda-captureopt ] lambda-parameter-list : ( parameter-declaration-clause ) lambda-parameter-list-and-specifiers : lambda-parameter-list lambda-specifiers lambda-declaratorlambda-specifiers :( parameter-declaration-clause )decl-specifier-seqoptnoexcept-specifieropt attribute-specifier-seqopt trailing-return-typeopt requires-clauseopt
Because parts of lambda-declarator have been renamed to lambda-parameter-list and lambda-specifiers, each reference to lambda-declarator must be updated.
Modify Function parameter scope [basic.scope.param] ❡1:
A function parameter (including one appearing in alambda-declaratorlambda-parameter-list ) or function-local predefined variable (9.5) has function parameter scope. [...]
Modify Lambda expressions [expr.prim.lambda.general] ❡3:
In the decl-specifier-seq of thelambda-declaratorlambda-specifiers , each decl-specifier shall be one of,
mutable , or
constexpr .
consteval
Modify Lambda expressions [expr.prim.lambda.general] ❡4:
If a lambda-expression does not include alambda-declaratorlambda-parameter-list , it is as if thelambda-declaratorlambda-parameter-list were. The lambda return type is
() , which is replaced by the type specified by the trailing-return-type if provided and/or deduced from
auto statements as described in 9.2.9.6.
return
Modify Closure types [expr.prim.lambda.closure] ❡2 Note 1:
This determines the set of namespaces and classes associated with the closure type (6.5.3). The parameter types of alambda-declaratorlambda-parameter-list do not affect these associated namespaces and classes.
Modify Closure types [expr.prim.lambda.closure] ❡3:
[...] The trailing requires-clause of the function call operator or operator template is the requires-clause following thelambda-declaratorlambda-parameter-list , if any.
Modify Closure types [expr.prim.lambda.closure] ❡4:
[...] An attribute-specifier-seq in alambda-declaratorlambda-specifiers appertains to the type of the corresponding function call operator or operator template. [...]
Modify Closure types [expr.prim.lambda.closure] ❡4 Note 3:
Names referenced in thelambda-declaratorlambda-parameter-list are looked up in the context in which the lambda-expression appears.
Modify Captures [expr.prim.lambda.capture] ❡5:
If an identifier in a simple-capture appears as the declarator-id of a parameter of thelambda-declaratorlambda-parameter-list ’s parameter-declaration-clause, the program is ill-formed.
Modify Default arguments [dcl.fct.default] ❡3:
A default argument shall be specified only in the parameter-declaration-clause of a function declaration orlambda-declaratorlambda-parameter-list or in a template-parameter (13.2); in the latter case, the initializer-clause shall be an assignment-expression. [...]
Modify Name resolution [temp.res.general] ❡5.2.5:
parameter-declaration in alambda-declaratorlambda-parameter-list or requirement-parameter-list, unless that parameter-declaration appears in a default argument, or