mercredi 28 novembre 2018

Why does [=]{} have a lambda capture?

At an intuitive level, it makes sense that a lambda that needs to carry no state (through a reference or otherwise) should be cleanly convertible to a naked function pointer. However, I was recently surprised to see the following failing in GCC, Clang, and MSVC:

int main(int, char *[]) {
    void (*fp)() = []{}; // OK
  //fp = [=]{};          // XXX - no user defined conversion operator available
  //fp = [&]{};          // XXX - same ...
}

The C++17 spec (or at least visible public draft version N4713), refers in item 7 of § 8.4.5.1 [expr.prim.lambda.closure] to lambdas with and without captures:

The closure type for a non-generic lambda-expression with no lambda-capture whose constraints (if any) are satisfied has a conversion function to pointer to function with C++ language linkage (10.5) having the same parameter and return types as the closure type’s function call operator. ...

However, looking into the formal grammar you can see the following in § 8.4.5 [expr.prim.lambda]:

  • lambda-expression :
    • lambda-introducer compound-statement
    • ...
  • lambda-introducer :
    • [ lambda-captureopt ]
  • ...

and in § 8.4.5.2 [expr.prim.lambda.capture]:

  • lambda-capture :
    • capture-default
    • capture-list
    • capture-default, capture-list
  • capture-default :
    • &
    • =

So all the compilers were actually obeying the letter of the law to my dismay...

Why does the language define the existence of a capture as a narrow grammatical distinction in the declaration instead of basing it on whether the body contains references to any non-static/captured state?

Aucun commentaire:

Enregistrer un commentaire