Search code examples
c++lambdalanguage-lawyerc++23

The validity of lambda expression with omitted parameter list in C++23


According to cppreference, both gcc and clang have completed the implementation of P1102R2 ("Down with ()!") recently, which means we can define lambda expressions more concisely in C++23.

But I found that they are inconsistent with a certain form:

auto l = []<auto> noexcept requires true {};

clang accepts this form, and gcc rejects its grammar.

Which compiler should I trust? Is this lambda well-formed or ill-formed in C++23?

Update:

Perhaps because of the pressure of public opinion, clang quickly fixed the 49736 within five days after I reported it.

As I tried further, I accidentally found out that gcc also rejected the following valid form, which made me report the 99850 and it was fixed after 2 weeks.

auto l = []<auto> requires true -> void {};

Solution

  • Thanks for reminding me of how pointless this feature is.

    The correct answer is: no, that's not a well-formed lambda. The grammar is defined in [expr.prim.lambda.general]:

    enter image description here

    In our case, to start with we have:

    []<auto> noexcept requires true {};
    
    • [] is the lambda-introducer
    • <auto> matches <template-parameter-list> and now we know we're the 2nd kind lambda-expression. So grammatically, we're need to follow with a requires-clause (optionally) then a lambda-declarator then a compound-statement.
    • noexcept does not match requires-clause, so now we're parsing a lambda-declarator. A lambda-declarator could start with (parameter-declaration-clause) but we don't have that, so we're just looking for lambda-specifiers. We consume the noexcept as part of noexcept-specifier.
    • requires true does not fit either attribute-specifier-seq or trailing-return-type so we have neither of those, and now we're done with lambda-specifiers so we're done with lambda-declarator. At this point, we're looking for a compound-statement. But we don't have that, so this is an error.

    Basically, there are two spots you can put a requires-clause: either directly after the template parameters or, if we have function parameters, after the lambda-specifiers after the function parameters. So this works:

    []<auto> requires true noexcept {};
    

    as does this:

    []<auto>() noexcept requires true {};
    

    as does this:

    []<auto> requires true () noexcept requires true { };
    

    But not the one in OP.

    Also, don't write this.